Reformat the test partition before each mount so those tests always start from
a known-empty filesystem.
Co-authored-by: Cursor <cursoragent@cursor.com>
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/
CVE-2026-6683 is an exFAT divide-by-zero: with NumClusters == 0 the filesystem
object has fs->n_fatent == 2, and the exFAT "percent in use" update in sync_fs()
computes ... * 100 / (fs->n_fatent - 2) -> division by zero.
That vulnerable exFAT PercInUse sync path was introduced in FatFs R0.16 and is
NOT present in this R0.15 release, so the divide-by-zero itself is not reachable
here. As defense-in-depth (and to keep parity with newer releases) reject an
empty exFAT cluster heap at mount time, which is a malformed volume regardless.
Record the CVE disposition 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/
When the NimBLE stack called this callback for a GATT Write Request, the
uninitialized stack value was interpreted as a non-zero GATT error code,
causing the stack to send BLE_ATT_ERR_UNLIKELY (0x0E) back to the client.
AVDT:
- Roll back CCB allocation when cmd/rsp queue creation fails
- Free media packet on invalid handle in AVDT_WriteReqOpt
- Zero-init timeout failure message before GETCAP callback
- Initialize lcid_tbl to 0xFF to avoid mapping to tc_tbl[0]
BTA/AVRCP:
- Use size_t for AVRC message copy buffer allocation
- Allocate before register in BTA_AvEnable
- Guard BTA_AvRegister callback when enable never completed
A2DP BTC/API:
- Default g_a2dp_on_deinit to true before profile init
- Add shutdown state check in btc_a2dp_sink_shutdown
- Guard A2DP source timer against freed dynamic local param
- advance connect queue on synchronous connect_cb failure
- lock bta_alarm_hash_map in all BTA timer APIs
- free controller params after stack disable; cleanup on init fail
- handle BTE_InitStack failure and signal init future
- validate HCI remote name event length before parse
- drop stale L2CAP quick-timer alarm events
- Fix connection failure when using RPA with whitelist filtering
- Fix disconnect with reason 0x08 during full scan
- Fix peer RPA resolution failure when advertising with a local identity address
Return BTM_HCI_ERROR | hci_status from legacy BLE 4.2 GAP HCI command
paths instead of mapping failures to BTM_ILLEGAL_VALUE or
BTM_NO_RESOURCES. Add btm_ble_status_from_hci() helper and propagate
real status through scan start/stop completion callbacks.
(cherry picked from commit 47dd785a18)
Co-authored-by: zhanghaipeng <zhanghaipeng@espressif.com>
Read By Type Response Length is one octet (max 255). When MTU was
large enough to return a long characteristic value in one pair, the
server wrote (UINT8)(value_len + 2) and overflowed (e.g. 513 -> 1),
so the client rejected the PDU as GATT_INVALID_PDU (0x04).
Cap server value to 253 bytes per pair, clamp the length byte, and
continue long reads via Read Blob when the capped size is returned.
(cherry picked from commit 97905afccc)
Co-authored-by: zhanghaipeng <zhanghaipeng@espressif.com>