mirror of
https://github.com/espressif/esp-idf.git
synced 2026-09-22 13:01:16 +03:00
fix(storage/fatfs): guard dirty-cache refill against unsigned LBA wrap (CVE-2026-6685)
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/
This commit is contained in:
@@ -8,3 +8,5 @@ cve-exclude-list:
|
||||
reason: Integer overflow in exFAT mount size validation. Patched by promoting the cluster-heap and bitmap-base multiplies to 64-bit in mount_volume().
|
||||
- cve: CVE-2026-6683
|
||||
reason: exFAT divide-by-zero when NumClusters == 0. Patched by rejecting an empty cluster heap at mount and guarding the divisor (n_fatent > 2) in sync_fs().
|
||||
- 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().
|
||||
|
||||
@@ -4084,11 +4084,11 @@ FRESULT f_read (
|
||||
if (disk_read(fs->pdrv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||
#if !FF_FS_READONLY && FF_FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
|
||||
#if FF_FS_TINY
|
||||
if (fs->wflag && fs->winsect - sect < cc) {
|
||||
if (fs->wflag && fs->winsect >= sect && fs->winsect - sect < cc) { /* CVE-2026-6685: guard against unsigned wrap when winsect < sect (mis-offset would be an OOB write into rbuff) */
|
||||
memcpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs));
|
||||
}
|
||||
#else
|
||||
if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {
|
||||
if ((fp->flag & FA_DIRTY) && fp->sect >= sect && fp->sect - sect < cc) { /* CVE-2026-6685: guard against unsigned wrap when fp->sect < sect (mis-offset would be an OOB write into rbuff) */
|
||||
memcpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs));
|
||||
}
|
||||
#endif
|
||||
@@ -4199,12 +4199,12 @@ FRESULT f_write (
|
||||
if (disk_write(fs->pdrv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
|
||||
#if FF_FS_MINIMIZE <= 2
|
||||
#if FF_FS_TINY
|
||||
if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
|
||||
if (fs->winsect >= sect && fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write (CVE-2026-6685: guard against unsigned wrap when winsect < sect) */
|
||||
memcpy(fs->win, wbuff + ((fs->winsect - sect) * SS(fs)), SS(fs));
|
||||
fs->wflag = 0;
|
||||
}
|
||||
#else
|
||||
if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
|
||||
if (fp->sect >= sect && fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write (CVE-2026-6685: guard against unsigned wrap when fp->sect < sect) */
|
||||
memcpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs));
|
||||
fp->flag &= (BYTE)~FA_DIRTY;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user