Validate MTU from DHCP option 26 against RFC 2132 minimum (68 bytes)
before applying to netif->mtu, preventing rogue DHCP servers from
setting MTU to 0 or other dangerously low values that cause integer
wraparound in IPv4 fragmentation.
Correct "802.154" to "802.15.4" and change the EUI-64 derivation notation
from base_mac[0:3]/base_mac[3:6] to the inclusive base_mac[0:2]/base_mac[3:5]
in the esp32h2/esp32h21/esp32h4 Kconfig.mac help text and the EN/zh_CN
misc_system_api docs.
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 811c64c17c)
Add help text to the esp32h2/esp32h21/esp32h4 Kconfig.mac explaining
that these chips only consume one universally administered MAC address:
the IEEE 802.154 EUI-64 is derived from the base MAC and MAC_EXT, and
Bluetooth reuses the base MAC as-is (no BT offset, since there is no
Wi-Fi).
Add a matching 1-MAC derivation table and note to misc_system_api.rst
(EN and zh_CN) under a new `.. only:: esp32h2 or esp32h21 or esp32h4`
block, and exclude these targets from the generic 4/2 table.
Add an esp32s31-only note stating that the "Four" option may only be
used with a customer-provided custom base MAC range, since ESP32-S31
only provides two universally administered MAC addresses in eFuse.
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit e3bc260178)
ESP32-H2/H21/H4 only provide a single universally administered MAC
address in eFuse (MAC_FACTORY), so switch their UNIVERSAL_MAC_ADDRESSES
Kconfig from "Two" to "One" to match the hardware allocation.
This is a functional no-op for MAC generation: the BT offset is only
applied when SOC_WIFI_SUPPORTED, and these chips have no Wi-Fi, so
Bluetooth already reuses the base MAC as-is; the IEEE 802.154 EUI-64 is
derived from the base MAC and MAC_EXT regardless. The only change is
the (otherwise unused) ESP_MAC_UNIVERSAL_MAC_ADDRESSES int value going
from 2 to 1.
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit 431983a091)
ESP32-S31 only provides two universally administered MAC addresses in
eFuse. The previous default of "Four" led to WiFi softap and Ethernet
consuming global MAC slots (base+1/+3) that do not exist on this chip
and could collide with the Bluetooth MAC.
Switch the default to "Two" so Softap and Ethernet fall back to locally
administered MACs derived from the WiFi station and Bluetooth MACs.
The "Four" option is retained for customers who override the base MAC
with a custom range in which four universally administered MAC
addresses are allocated per device; the help text now documents this
constraint.
Co-authored-by: Cursor <cursoragent@cursor.com>
(cherry picked from commit f18f3814cc)
The initial CVE-2026-6682 fix hardened the exFAT mount path, but the CVE
as reported by runZero is a FAT32 defect in mount_volume() and is
reachable in the default configuration (exFAT and 64-bit LBA disabled).
This corrects the fix.
Root cause: `fasize *= fs->n_fats` is a DWORD multiply with no overflow
guard. A crafted BPB_FATSz32 such as 0x80000001 with NumFATs=2 wraps
`fasize` to 0x00000002. The wrapped (too-small) FAT size places
`fs->database` inside the FAT region, so a forged directory entry yields
an attacker-controlled `finfo.fsize`; a caller using it as a read length
overflows its buffer with attacker-controlled bytes (CVSS 7.6).
Fix: reject per-FAT and reserved+FAT+root system-area sizes that overflow
DWORD before they are used to derive the data-area base. The exFAT
cluster-heap/bitmap 64-bit promotions are retained as defense-in-depth
and relabeled (they are not CVE-2026-6682). SBOM reason updated.
Document the three runZero "Seven FatFs bugs" CVEs that require no source change
in this component, so vulnerability scanners have their disposition:
- CVE-2026-6684: GPT partition-scan loop DoS. Already fixed upstream in R0.16,
where test_gpt_header() caps the partition-entry count at 128.
- CVE-2026-6686: read of uninitialized clusters after f_lseek() past EOF.
Longstanding, behavioral; not a memory-safety defect and zero-filling every
extended cluster is prohibitively costly on flash.
- CVE-2026-6688: long-filename overflow in downstream callers. Not exposed in
ESP-IDF; vfs_fat.c uses bounded copies and fname is bounded by FF_MAX_LFN.
Reference: https://www.runzero.com/blog/fatfs-bugs/
f_getlabel() extracts the exFAT volume label with a loop bounded by the on-disk
byte dj.dir[XDIR_NumLabel] (0-255):
for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++)
wc = ld_16(dj.dir + XDIR_Label + si * 2);
The exFAT label field holds at most 11 UTF-16 units (22 bytes). A crafted
directory entry with a larger count both reads past the 22-byte label field and,
through put_utf(... &label[di], 4), writes past the end of the caller-provided
label buffer (the canonical API examples use small fixed stack buffers) -> stack
buffer overflow.
Clamp the character count to the exFAT maximum of 11 before the extraction loop.
Record the CVE in the component SBOM.
Note: f_getlabel() takes no destination-buffer size, so under UTF-8 output
(FF_LFN_UNICODE == 2) 11 units can still expand to up to 34 bytes; the clamp
downgrades this from attacker-unbounded to spec-bounded. ESP-IDF's VFS layer
does not call f_getlabel(); direct callers on untrusted media should size their
buffer accordingly. A complete fix requires an upstream size-aware API change.
Reference: https://www.runzero.com/blog/fatfs-bugs/
After a direct multi-sector disk_read()/disk_write(), FatFs decides whether the
cached sector overlaps the direct-I/O range with:
fp->sect - sect < cc (and the FF_FS_TINY variant fs->winsect - sect < cc)
`sect`, `fp->sect` and `fs->winsect` are unsigned LBA_t. On 32-bit LBA_t builds,
if the cached sector is below `sect`, the subtraction wraps to a huge value that
can still compare `< cc`, so the code computes a bogus large offset:
- in f_write() it mis-copies from the direct write buffer (data corruption);
- in f_read() it is worse: memcpy(rbuff + (wrapped_offset * SS), ...) is an
out-of-bounds WRITE into the caller-supplied read buffer.
Add an explicit lower-bound check (fp->sect >= sect, resp. fs->winsect >= sect)
before the range test on both the read and write paths and both the FF_FS_TINY
and normal variants, so the condition is exactly "cached sector lies within
[sect, sect + cc)". Record the CVE in the component SBOM.
Reference: https://www.runzero.com/blog/fatfs-bugs/
The FAT12/16/32 mount path rejects a zero cluster count, but the exFAT path
accepted NumClusters == 0. That yields fs->n_fatent == 2, and sync_fs() later
computes the "percent in use" field as:
... * 100 / (fs->n_fatent - 2)
which is a division by zero (n_fatent - 2 == 0) -> crash. On a device that
syncs during an update this can brick the unit.
Reject ncl == 0 at exFAT mount time, and add a defense-in-depth
`fs->n_fatent > 2` guard around the division in sync_fs() so the divisor can
never be zero even if some future path produces such a filesystem object.
Record the CVE in the component SBOM.
Reference: https://www.runzero.com/blog/fatfs-bugs/
The exFAT mount path validates that the media is large enough to hold the
declared cluster heap with:
if (maxlba < (QWORD)fs->database + ncl * fs->csize) ...
`ncl` (DWORD, up to MAX_EXFAT) and `fs->csize` (WORD) are both promoted to
`unsigned int`, so `ncl * fs->csize` is evaluated in 32-bit arithmetic and can
wrap before the QWORD promotion of the sum. A crafted image with a large
NumClusters/SecPerClus can therefore make an undersized volume pass the "size
is large enough" check; subsequent cluster->sector math then addresses media
outside the actual device.
Promote the multiply to 64-bit ((QWORD)ncl * fs->csize). Apply the same
promotion to the bitmap-base computation ((LBA_t)fs->csize * (bcl - 2)), which
has the identical overflow shape. Record the CVE in the component SBOM.
Reference: https://www.runzero.com/blog/fatfs-bugs/
The vendored FatFs sources are revision R0.16 (FF_DEFINED == 80386, per
components/fatfs/src/ff.h and ff.c) but the SBOM recorded R0.15. Correct the
recorded version so vulnerability tracking matches the actual sources.
The reassembly buffer must be reset to its origin at the beginning of every
transaction. prov_msg_recv() pulls the PDU type byte (advancing buf->data by
one) and nothing restores it between transactions. Without this reset,
buf->data drifts forward by one byte per received PDU, causing the segment-0
memcpy to write past the end of the statically allocated rx buffer
(PROV_RX_BUF_SIZE), and the XACT_SEG_DATA() offsets used for continuation
segments to be skewed by the accumulated drift.
(cherry picked from commit 2c4acaa2aa)
Co-authored-by: luoxu <luoxu@espressif.com>
Fix multiple wire-format and robustness issues in the DFD client
(dfd_cli.c):
- handle_capabilities: read oob_retrieval_supported as u8 instead of
le32. The server encodes a single byte; le32 over-consumed 3 bytes
of the URL scheme list and could over-read the buffer.
- handle_upload_status: extract upload_progress from bits 0-6 (& 0x7F)
and upload_type from bit 7 (>> 7), matching the server encoding
(progress | BIT(7)). The previous >>1 / &0x01 returned wrong values,
mis-classified in-band vs OOB, and falsely rejected valid OOB
messages with high progress.
- handle_dfd_status: correct the transfer-mode byte layout to
trans_mode bits 0-1, update_policy bit 2, RFU bits 3-7 (previously
read bits 6-7 / 5), and fix the RFU mask to 0xF8. Now matches the
struct bitfield definition and the DFD server.
- handle_dfd_status: report status+phase and return early when
buf->len == 0 (IDLE phase) instead of pulling 10 absent bytes.
- bt_mesh_dfd_cli_distribution_start: encode trans_mode/update_policy
into bits 0-2 so the server decodes them correctly.
- handle_receiver_list: validate buf->len >= entries_cnt * 5 before
the loop, and handle entries_cnt == 0 without relying on calloc(0).
- handle_receiver_status: pass the status value (not the whole union)
to the %d log format, fixing undefined behavior.
- dfd_client_recv_status: drop the dead BLE_MESH_DFD_OP_CAPABILITIES_GET
case (a client-send opcode) from the receive switch.
- bt_mesh_dfd_cli_receivers_add: widen msg_length to uint32_t to avoid
uint16_t overflow that bypassed the PDU size guard; add a NULL check
for the receivers array.
- bt_mesh_dfd_cli_distribution_upload_oob_start: return -EINVAL
instead of -1 for consistency with the rest of the file.
(cherry picked from commit 43137475e1)
Co-authored-by: luoxu <luoxu@espressif.com>