From a8ff47bfe7ac29bc5736b4334e9a2c03be2c5c4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Rohl=C3=ADnek?= Date: Mon, 6 Jul 2026 13:38:59 +0200 Subject: [PATCH] fix(storage/fatfs): clamp exFAT volume-label length in f_getlabel() (CVE-2026-6687) 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/ --- components/fatfs/sbom.yml | 2 ++ components/fatfs/src/ff.c | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/components/fatfs/sbom.yml b/components/fatfs/sbom.yml index 6c994059fbb..6a11a9eddda 100644 --- a/components/fatfs/sbom.yml +++ b/components/fatfs/sbom.yml @@ -10,3 +10,5 @@ cve-exclude-list: reason: exFAT divide-by-zero when NumClusters == 0. The vulnerable exFAT PercInUse sync division was introduced in R0.16 and is not present in this R0.15 release; an empty cluster heap is additionally rejected at mount as defense-in-depth. - cve: CVE-2026-6685 reason: Unsigned-subtraction wrap in the dirty-cache refill check. Patched by requiring the cached sector to lie within the direct-I/O range in both f_write() and f_read(). + - cve: CVE-2026-6687 + reason: exFAT label-length overflow in f_getlabel(). Patched by clamping XDIR_NumLabel to the 11-unit exFAT label maximum. diff --git a/components/fatfs/src/ff.c b/components/fatfs/src/ff.c index 163bdc16c17..f1a021e2c65 100644 --- a/components/fatfs/src/ff.c +++ b/components/fatfs/src/ff.c @@ -5408,9 +5408,11 @@ FRESULT f_getlabel ( #if FF_FS_EXFAT if (fs->fs_type == FS_EXFAT) { WCHAR hs; - UINT nw; + UINT nw, nchar; - for (si = di = hs = 0; si < dj.dir[XDIR_NumLabel]; si++) { /* Extract volume label from 83 entry */ + nchar = dj.dir[XDIR_NumLabel]; /* Number of UTF-16 characters in the label entry */ + if (nchar > 11) nchar = 11; /* CVE-2026-6687: clamp to the exFAT maximum (11) to prevent OOB read of the entry and overflow of the caller label buffer */ + for (si = di = hs = 0; si < nchar; si++) { /* Extract volume label from 83 entry */ wc = ld_word(dj.dir + XDIR_Label + si * 2); if (hs == 0 && IsSurrogate(wc)) { /* Is the code a surrogate? */ hs = wc; continue;