From: "Jianzhou Zhao" <luckd0g@163.com>
To: linux-fsdevel@vger.kernel.org, viro@zeniv.linux.org.uk,
brauner@kernel.org, jack@suse.cz, linux-kernel@vger.kernel.org
Subject: KCSAN: data-race in step_into_slowpath / vfs_unlink
Date: Wed, 11 Mar 2026 15:55:29 +0800 (CST) [thread overview]
Message-ID: <2b8b707a.6a35.19cdbe4c889.Coremail.luckd0g@163.com> (raw)
Subject: [BUG] fs: KCSAN: data-race in step_into_slowpath / vfs_unlink
Dear Maintainers,
We are writing to report a KCSAN-detected data race vulnerability within the VFS subsystem (`fs/namei.c` and `include/linux/dcache.h`). This bug was found by our custom fuzzing tool, RacePilot. The race concerns the `d_flags` field of a `dentry` structure: `dont_mount()` modifies the flags concurrently with lockless RCU path walks checking `d_is_symlink()` inside `step_into_slowpath()`. We observed this bug on the Linux kernel version 6.18.0-08691-g2061f18ad76e-dirty.
Call Trace & Context
==================================================================
BUG: KCSAN: data-race in step_into_slowpath / vfs_unlink
write to 0xffff8880134699c0 of 4 bytes by task 3611 on cpu 1:
dont_mount home/kfuzz/linux/include/linux/dcache.h:391 [inline]
vfs_unlink+0x37d/0x6e0 home/kfuzz/linux/fs/namei.c:5392
do_unlinkat+0x301/0x4e0 home/kfuzz/linux/fs/namei.c:5460
__do_sys_unlink home/kfuzz/linux/fs/namei.c:5495 [inline]
...
read to 0xffff8880134699c0 of 4 bytes by task 3015 on cpu 0:
__d_entry_type home/kfuzz/linux/include/linux/dcache.h:425 [inline]
d_is_symlink home/kfuzz/linux/include/linux/dcache.h:455 [inline]
step_into_slowpath+0x11d/0x910 home/kfuzz/linux/fs/namei.c:2068
step_into home/kfuzz/linux/fs/namei.c:2119 [inline]
walk_component home/kfuzz/linux/fs/namei.c:2258 [inline]
lookup_last home/kfuzz/linux/fs/namei.c:2753 [inline]
path_lookupat+0x422/0x740 home/kfuzz/linux/fs/namei.c:2777
filename_lookup+0x1d3/0x3f0 home/kfuzz/linux/fs/namei.c:2806
do_readlinkat.part.0+0x5f/0x250 home/kfuzz/linux/fs/stat.c:594
...
value changed: 0x00300080 -> 0x00004080
Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 3015 Comm: systemd-udevd Not tainted 6.18.0-08691-g2061f18ad76e-dirty #42 PREEMPT(voluntary)
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014
==================================================================
Execution Flow & Code Context
The race occurs when a process is unlinking a file (`vfs_unlink`). As part of removing the dentry, VFS utilizes `dont_mount` to guarantee the dentry is flagged as `DCACHE_CANT_MOUNT`, preventing further interactions spanning mount layers. This operation applies a spinlock around the mutation:
```c
// include/linux/dcache.h
static inline void dont_mount(struct dentry *dentry)
{
spin_lock(&dentry->d_lock);
dentry->d_flags |= DCACHE_CANT_MOUNT; // <-- Modifies d_flags
spin_unlock(&dentry->d_lock);
}
```
However, another concurrent process resolving paths (e.g., executing `readlinkat`) may traverse through `step_into()` into `step_into_slowpath()`. The slowpath evaluates whether to follow symbolic links using `d_is_symlink()`, which executes a lockless read on `dentry->d_flags`:
```c
// include/linux/dcache.h
static inline unsigned __d_entry_type(const struct dentry *dentry)
{
return dentry->d_flags & DCACHE_ENTRY_TYPE; // <-- Plain concurrent read
}
static inline bool d_is_symlink(const struct dentry *dentry)
{
return __d_entry_type(dentry) == DCACHE_SYMLINK_TYPE;
}
```
Root Cause Analysis
A KCSAN data race arises because one thread configures the internal `d_flags` synchronously within a spinlock but without explicit compiler bounds (`WRITE_ONCE`), while a second thread concurrently navigates the paths. `__d_entry_type` evaluates `dentry->d_flags` via a plain read (`& DCACHE_ENTRY_TYPE`). Because path lookups are largely optimized locklessly (RCU walks), `d_flags` bits can fluctuate concurrently. The writer changes `DCACHE_CANT_MOUNT` bits which inadvertently triggers standard diagnostics against the masking read of the entry type.
Unfortunately, we were unable to generate a reproducer for this bug.
Potential Impact
This data race is functionally benign. The type encoding bits `DCACHE_ENTRY_TYPE` are initialized when the dentry is instantiated and they do not shift dynamically for a specific live dentry pointer instance. The concurrent mutation only manipulates disjoint bit ranges (like `DCACHE_CANT_MOUNT`). However, the lack of annotations can trigger compiler tearing optimisations on architectures with distinct load/store granularities or simply pollute logs with false positive alarms, obscuring valid concurrency issues.
Proposed Fix
To accurately reflect the RCU memory model design that allows lockless reads of `d_flags` bits against asynchronous modifiers acting on orthogonal masks, we should decorate the read access in `__d_entry_type` with the `data_race()` marker.
```diff
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -426,7 +426,7 @@ static inline bool d_mountpoint(const struct dentry *dentry)
*/
static inline unsigned __d_entry_type(const struct dentry *dentry)
{
- return dentry->d_flags & DCACHE_ENTRY_TYPE;
+ return data_race(dentry->d_flags) & DCACHE_ENTRY_TYPE;
}
static inline bool d_is_miss(const struct dentry *dentry)
```
We would be highly honored if this could be of any help.
Best regards,
RacePilot Team
next prev reply other threads:[~2026-03-11 7:55 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-11 8:02 KCSAN: data-race in __d_drop / retain_dentry Jianzhou Zhao
2026-03-11 7:55 ` Jianzhou Zhao [this message]
2026-03-11 7:49 ` KCSAN: data-race in __remove_assoc_queue / mark_buffer_dirty_inode Jianzhou Zhao
2026-03-11 2:54 ` KCSAN: data-race in path_lookupat / vfs_rename Jianzhou Zhao
2026-03-11 10:38 ` KCSAN: data-race in __d_drop / retain_dentry Christian Brauner
2026-03-17 12:37 ` KCSAN: data-race in __remove_assoc_queue / mark_buffer_dirty_inode Jan Kara
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2b8b707a.6a35.19cdbe4c889.Coremail.luckd0g@163.com \
--to=luckd0g@163.com \
--cc=brauner@kernel.org \
--cc=jack@suse.cz \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox