KCSAN: data-race in _copy_to_iter / fat12_ent_put (9)

Status: moderation: reported on 2026/11/01 22:47
Subsystems: exfat
Labels: prio:low race:benign
[Documentation on labels]
Reported-by: syzbot+bd0378ab4a6217b84474@syzkaller.appspotmail.com
First crash: 15h40m, last: 15h36m
✨ AI-generated root cause summary:

A data race occurs between an in-place FAT12 metadata update and a concurrent read of the underlying block device from userspace. In fs/fat/fatent.c, fat12_ent_put() modifies a 12-bit FAT table entry in-place inside fatent->bhs[0]->b_data. Because sb_bread() buffers are backed by folios in the block device's page cache (sb->s_bdev->bd_inode->i_mapping), this memory is shared with direct block device reads. Concurrently, a userspace process (such as udevd) reading directly from the block device node invokes blkdev_read_iter() -> filemap_read(), which copies the folio to userspace via _copy_to_iter() without holding a lock on the folio, leading to the KCSAN data-race report.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit cbbddb6b08cc:

Technical Root Cause Analysis

1. Components and Functions Involved

  • Filesystem metadata writer (fs/fat/fatent.c, fs/fat/misc.c, fs/fat/file.c):
    • fat_fallocate() / fat_cont_expand() / fat_chain_add() / fat_ent_write()
    • fat12_ent_put(struct fat_entry *fatent, int new): Updates a 12-bit entry in the FAT table in-place via pointer fatent->u.ent12_p[0], which points into fatent->bhs[0]->b_data.
    • fat12_entry_lock: Internal spinlock guarding non-byte-aligned FAT12 entry bit modifications across FAT internal operations.
  • Block device reader (block/fops.c, mm/filemap.c, lib/iov_iter.c):
    • blkdev_read_iter(): Called when a userspace process (here, udevd) performs a buffered read() directly on the block device node (e.g., /dev/sdX or /dev/loopX).
    • filemap_read(): Reads the cached folio from the block device's address space (bd_inode->i_mapping).
    • copy_folio_to_iter() -> _copy_to_iter() -> copy_to_user_iter(): Copies data from the kernel pagecache folio into userspace.

2. Detailed Mechanism and Trigger

  1. Shared Buffer Storage: When the FAT filesystem reads or modifies metadata sectors (the File Allocation Table), it calls sb_bread(sb, blocknr). In Linux, sb_bread() allocates buffer heads (struct buffer_head) backed by pages/folios in the block device's address space (sb->s_bdev->bd_inode->i_mapping). Thus, fatent->bhs[0]->b_data points directly into the memory of a pagecache folio belonging to the block device.

  2. In-place Filesystem Update (Writer): When extending a file (fallocate -> fat_cont_expand), FAT needs to link a new cluster into the cluster chain via fat_chain_add() -> fat_ent_write() -> ops->ent_put(). For FAT12, fat12_ent_put() acquires fat12_entry_lock and updates the entry directly in memory:

    *ent12_p[0] = new & 0xff;
    

    This writes 1 byte into the buffer head's data at byte offset 0x94.

  3. Concurrent Raw Block Device Read (Reader): Concurrently, a userspace system daemon (udevd) opens the underlying block device directly and issues a read() (e.g. probing partition tables, filesystem signatures, or volume labels). blkdev_read_iter() takes inode_lock_shared(bd_inode) and calls filemap_read(). In filemap_read(), folios matching the requested file range are obtained from bd_inode->i_mapping. filemap_read() calls copy_folio_to_iter(), which reads the 512-byte sector at 0xffff888124d81000 into userspace via _copy_to_iter().

  4. Synchronization Gap and KCSAN Detection: Pagecache reads in filemap_read() intentionally do not hold the folio lock across copy_folio_to_iter() to prevent ABBA deadlocks should a user-provided buffer fault into the same address space. Furthermore, blkdev_read_iter() only synchronizes against raw block device pagecache invalidations via inode_lock_shared(bd_inode). Filesystem metadata modifications made via buffer heads (b_data) synchronize only with filesystem-internal locks (such as fat12_entry_lock), with no locking against direct, concurrent userspace reads on the raw block device node. As a result, CPU 0 writes to 0xffff888124d81094 while CPU 1 reads [0xffff888124d81000, 0xffff888124d81200), triggering the KCSAN data-race warning.

▶ ▼ ✨ AI Jobs (3)
ID Workflow Result Correct Bug Created Started Finished Revision
a090a786 assessment-security DenialOfService: ❌ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ❌ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ KCSAN: data-race in _copy_to_iter / fat12_ent_put (9) 2026/11/01 22:47 2026/11/01 22:47 2026/11/01 23:46 25a0ae84
3357acaa assessment-kcsan Benign: ✅ ❓ KCSAN: data-race in _copy_to_iter / fat12_ent_put (9) 2026/11/01 22:46 2026/11/01 22:47 2026/11/01 23:33 25a0ae84
c11cd97d assessment-kcsan Benign: ✅ ❓ KCSAN: data-race in _copy_to_iter / fat12_ent_put (9) 2026/11/01 22:46 2026/11/01 22:47 2026/11/02 00:16 25a0ae84
▶ ▼ Similar bugs (8)
Kernel Title Rank 🛈 Repro Cause bisect Fix bisect Count Last Reported Patched Status
upstream KCSAN: data-race in _copy_to_iter / fat12_ent_put exfat 6 6 1514d 1545d 0/29 auto-obsoleted due to no activity on 2022/10/14 22:33
upstream KCSAN: data-race in _copy_to_iter / fat12_ent_put (7) exfat 6 5 291d 426d 0/29 auto-obsoleted due to no activity on 2026/03/12 02:36
upstream KCSAN: data-race in _copy_to_iter / fat12_ent_put (4) exfat 6 5 1254d 1284d 0/29 auto-obsoleted due to no activity on 2023/07/02 02:14
upstream KCSAN: data-race in _copy_to_iter / fat12_ent_put (5) exfat 6 21 1074d 1059d 0/29 auto-obsoleted due to no activity on 2023/12/28 22:56
upstream KCSAN: data-race in _copy_to_iter / fat12_ent_put (6) exfat 6 1 977d 977d 0/29 auto-obsoleted due to no activity on 2024/04/04 01:15
upstream KCSAN: data-race in _copy_to_iter / fat12_ent_put (3) exfat 6 3 1328d 1344d 0/29 auto-obsoleted due to no activity on 2023/04/24 07:39
upstream KCSAN: data-race in _copy_to_iter / fat12_ent_put (8) prio:low exfat 6 4 69d 199d 0/29 auto-obsoleted due to no activity on 2026/10/20 13:18
upstream KCSAN: data-race in _copy_to_iter / fat12_ent_put (2) exfat 6 3 1444d 1478d 0/29 auto-obsoleted due to no activity on 2022/12/31 00:12

Sample crash report:
==================================================================
BUG: KCSAN: data-race in _copy_to_iter / fat12_ent_put

write to 0xffff888120a43e8d of 1 bytes by task 7187 on cpu 1:
 fat12_ent_put+0x74/0x180 fs/fat/fatent.c:168
 fat_ent_write+0x76/0x160 fs/fat/fatent.c:422
 fat_chain_add+0x178/0x490 fs/fat/misc.c:138
 fat_add_clusters fs/fat/inode.c:114 [inline]
 __fat_get_block fs/fat/inode.c:156 [inline]
 fat_get_block+0x468/0x5e0 fs/fat/inode.c:191
 __block_write_begin_int+0x421/0x1060 fs/buffer.c:2031
 block_write_begin fs/buffer.c:2145 [inline]
 cont_write_begin+0x5bf/0x920 fs/buffer.c:2507
 fat_write_begin+0x52/0xe0 fs/fat/inode.c:231
 cont_expand_zero fs/buffer.c:2435 [inline]
 cont_write_begin+0x18d/0x920 fs/buffer.c:2497
 fat_write_begin+0x52/0xe0 fs/fat/inode.c:231
 generic_cont_expand_simple+0xb0/0x150 fs/buffer.c:2398
 fat_cont_expand+0x3e/0x170 fs/fat/file.c:226
 fat_fallocate+0x168/0x1a0 fs/fat/file.c:302
 vfs_fallocate+0x3ac/0x400 fs/open.c:338
 ksys_fallocate fs/open.c:362 [inline]
 __do_sys_fallocate fs/open.c:367 [inline]
 __se_sys_fallocate fs/open.c:365 [inline]
 __x64_sys_fallocate+0x7a/0xd0 fs/open.c:365
 x64_sys_call+0x1e1d/0x2550 arch/x86/include/generated/asm/syscalls_64.h:286
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x112/0x360 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

read to 0xffff888120a43e00 of 512 bytes by task 4572 on cpu 0:
 instrument_copy_to_user include/linux/instrumented.h:130 [inline]
 copy_to_user_iter lib/iov_iter.c:24 [inline]
 iterate_ubuf include/linux/iov_iter.h:30 [inline]
 iterate_and_advance2 include/linux/iov_iter.h:302 [inline]
 iterate_and_advance include/linux/iov_iter.h:332 [inline]
 _copy_to_iter+0x130/0xea0 lib/iov_iter.c:197
 copy_page_to_iter+0x174/0x210 lib/iov_iter.c:374
 copy_folio_to_iter include/linux/uio.h:212 [inline]
 filemap_read+0x3f8/0xad0 mm/filemap.c:2893
 blkdev_read_iter+0x29c/0x390 block/fops.c:896
 new_sync_read fs/read_write.c:493 [inline]
 vfs_read+0x699/0x7c0 fs/read_write.c:574
 ksys_read+0xdc/0x1a0 fs/read_write.c:716
 __do_sys_read fs/read_write.c:725 [inline]
 __se_sys_read fs/read_write.c:723 [inline]
 __x64_sys_read+0x40/0x50 fs/read_write.c:723
 x64_sys_call+0x2135/0x2550 arch/x86/include/generated/asm/syscalls_64.h:1
 do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
 do_syscall_64+0x112/0x360 arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe+0x77/0x7f

Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 4572 Comm: udevd Tainted: G        W           syzkaller #0 PREEMPT(lazy) 
Tainted: [W]=WARN
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/07/2026
==================================================================

Crashes (2):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/11/01 22:50 upstream cbbddb6b08cc 25a0ae84 .config console log report info [disk image] [vmlinux] [kernel image] ci2-upstream-kcsan-gce KCSAN: data-race in _copy_to_iter / fat12_ent_put
2026/11/01 22:46 upstream cbbddb6b08cc 25a0ae84 .config console log report info [disk image] [vmlinux] [kernel image] ci2-upstream-kcsan-gce KCSAN: data-race in _copy_to_iter / fat12_ent_put
* Struck through repros no longer work on HEAD.