KCSAN: data-race in __follow_mount_rcu / __unlock_mount

Status: moderation: reported on 2026/10/25 19:41
Subsystems: fs
Labels: race:benign prio:low
[Documentation on labels]
Reported-by: syzbot+b9be4fa709d8c4de099c@syzkaller.appspotmail.com
First crash: 2d13h, last: 2d13h
✨ AI-generated root cause summary:
A data race occurs between __follow_mount_rcu() in fs/namei.c and maybe_free_mountpoint() in fs/namespace.c on dentry->d_flags. During RCU-mode path walk, __follow_mount_rcu() performs unmarked reads of dentry->d_flags without holding dentry->d_lock. Concurrently, a mount operation cleans up an unused mountpoint in maybe_free_mountpoint() by clearing DCACHE_MOUNTED on the target dentry via an unmarked read-modify-write under dentry->d_lock and mount_lock. In production builds, this data race is benign: the access is naturally aligned (32-bit), and any transient inconsistency is caught by mount_lock sequence count verification (read_seqretry(&mount_lock, nd->m_seq)), falling back safely to non-RCU path walk.
▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit 21a7f44fd076:
### 1. Root Cause Analysis The reported Kernel Concurrency Sanitizer (KCSAN) data race occurs on the 4-byte `d_flags` field of `struct dentry` between `__follow_mount_rcu()` in `fs/namei.c` and `maybe_free_mountpoint()` in `fs/namespace.c`: - **Reader side (`task 12655`, `fs/namei.c:1714`):** During RCU path walk (`LOOKUP_RCU`), the kernel executes `step_into()` -> `step_into_slowpath()` -> `handle_mounts()` -> `__follow_mount_rcu()`. When following mounts across mountpoints (or stacked mounts where the target is a mount's root `mounted->mnt.mnt_root`), `__follow_mount_rcu()` samples `dentry->d_flags` (`flags = dentry->d_flags;`) without acquiring `dentry->d_lock` and without using concurrency-marking primitives such as `READ_ONCE()` or `data_race()`. - **Writer side (`task 12654`, `fs/namespace.c:979`):** Concurrently, another task is performing a mount operation via `do_mount()` -> `path_mount()` -> `do_new_mount()` -> `do_new_mount_fc()`. While locking the mount target, `do_lock_mount()` calls `get_mountpoint()`, which attaches a pinned mountpoint (`d_set_mounted(dentry)` sets `dentry->d_flags |= DCACHE_MOUNTED`). When `do_new_mount_fc()` completes or fails (e.g., `do_add_mount()` error) and cleans up via `__cleanup(unlock_mount)` -> `unlock_mount()` -> `__unlock_mount()` -> `unpin_mountpoint()`, it invokes `maybe_free_mountpoint()`. Because no mounts remain attached to this mountpoint structure, it clears the flag: ```c spin_lock(&dentry->d_lock); dentry->d_flags &= ~DCACHE_MOUNTED; spin_unlock(&dentry->d_lock); ``` This is a plain read-modify-write on `dentry->d_flags` while holding `dentry->d_lock` and `read_seqlock_excl(&mount_lock)`. Because the read in `__follow_mount_rcu()` is neither locked nor annotated with `READ_ONCE()`, KCSAN flags the concurrent unsynchronized access as a data race. --- ### 2. Runtime Consequences in Production Builds In a production kernel without debugging sanitizers (KCSAN, KASAN, etc.): - **Memory Corruption (`false`):** The accessed `dentry->d_flags` field is a 32-bit naturally aligned integer. On all supported architectures, single-word aligned reads and writes are atomic with respect to word tearing. - **Denial of Service (`false`):** The value read into `flags` in `__follow_mount_rcu()` is only tested for specific bit flags (`DCACHE_MANAGE_TRANSIT`, `DCACHE_MOUNTED`, and `DCACHE_NEED_AUTOMOUNT`). Furthermore, all mount tree mutations in `__unlock_mount()` occur under `read_seqlock_excl(&mount_lock)`. If `__follow_mount_rcu()` reads a stale or changing state of `dentry->d_flags`, it immediately verifies the mount generation sequence via `read_seqretry(&mount_lock, nd->m_seq)`. If any modification occurred, `__follow_mount_rcu()` returns `false`, gracefully aborting RCU-walk mode and falling back to ref-walk mode via `try_to_unlazy_next()` / `traverse_mounts()`. No deadlocks, panics, or hangs occur. - **Information Leak (`"none"`):** No uninitialized data or kernel pointers are exposed or leaked to userspace. - **Candidate Classifications (`IsNetCandidate = false`, `IsKVMCandidate = false`):** The bug is entirely contained within the VFS path lookup and namespace mounting subsystems (`fs/namei.c` and `fs/namespace.c`).
▶ ▼ ✨ AI Jobs (2)
ID Workflow Result Correct Bug Created Started Finished Revision
d0bc5a6b assessment-security DenialOfService: ❌ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ✅ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ KCSAN: data-race in __follow_mount_rcu / __unlock_mount 2026/10/27 04:15 2026/10/27 04:15 2026/10/27 04:42 168cb7a2
61aeedcb assessment-kcsan Benign: ✅ ❓ KCSAN: data-race in __follow_mount_rcu / __unlock_mount 2026/10/25 19:40 2026/10/25 19:41 2026/10/25 20:29 1d9ca40b

Sample crash report:
==================================================================
BUG: KCSAN: data-race in __follow_mount_rcu / __unlock_mount

read to 0xffff888105a4ce40 of 4 bytes by task 12655 on cpu 0:
 __follow_mount_rcu+0x156/0x2a0 fs/namei.c:1714
 handle_mounts fs/namei.c:1740 [inline]
 step_into_slowpath+0x30c/0x4c0 fs/namei.c:2104
 step_into fs/namei.c:2152 [inline]
 walk_component fs/namei.c:2288 [inline]
 link_path_walk+0x953/0xde0 fs/namei.c:-1
 path_openat+0x142/0x11c0 fs/namei.c:5006
 do_file_open+0x16c/0x290 fs/namei.c:5039
 do_sys_openat2+0xa1/0x140 fs/open.c:1442
 do_sys_open fs/open.c:1448 [inline]
 __do_sys_openat fs/open.c:1464 [inline]
 __se_sys_openat fs/open.c:1459 [inline]
 __x64_sys_openat+0xf2/0x120 fs/open.c:1459
 x64_sys_call+0x1f72/0x2550 arch/x86/include/generated/asm/syscalls_64.h:258
 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-write to 0xffff888105a4ce40 of 4 bytes by task 12654 on cpu 1:
 maybe_free_mountpoint fs/namespace.c:979 [inline]
 unpin_mountpoint fs/namespace.c:994 [inline]
 __unlock_mount+0x142/0x1f0 fs/namespace.c:2905
 unlock_mount fs/namespace.c:2913 [inline]
 do_new_mount_fc fs/namespace.c:3933 [inline]
 do_new_mount+0x583/0x730 fs/namespace.c:3986
 path_mount+0x4ad/0xb90 fs/namespace.c:4337
 do_mount fs/namespace.c:4350 [inline]
 __do_sys_mount fs/namespace.c:4565 [inline]
 __se_sys_mount+0x28c/0x2e0 fs/namespace.c:4542
 __x64_sys_mount+0x67/0x80 fs/namespace.c:4542
 x64_sys_call+0xc3b/0x2550 arch/x86/include/generated/asm/syscalls_64.h:166
 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: 1 UID: 0 PID: 12654 Comm: syz.1.2844 Not tainted syzkaller #0 PREEMPT(lazy) 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/07/2026
==================================================================

Crashes (1):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/10/25 19:40 upstream 21a7f44fd076 1d9ca40b .config console log report info [disk image] [vmlinux] [kernel image] ci2-upstream-kcsan-gce KCSAN: data-race in __follow_mount_rcu / __unlock_mount
* Struck through repros no longer work on HEAD.