From nobody Thu Apr 9 04:04:24 2026 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 31844258CD7; Wed, 11 Mar 2026 07:55:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.3 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773215752; cv=none; b=GDbIOCFo6BrzfRq9x+ABEvD8ELUefzQyctMMawXvtWP3D4DwI+GQXGdYHRpc09yTSyPoLDhZ0u2/4cehBog0A70NQ2v5f+Z+a0mPTZT98gGVvB4/SHr01tBgWw0vfhmPrRg0A2nNcxkJ/+wZV3U0Vv9xhwp5thtCTMdHliIvt5w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1773215752; c=relaxed/simple; bh=D6uWziG+lgdgpLtMcbOSPZAGmmkhOHvBN4q4YiTEeyQ=; h=Date:From:To:Subject:Content-Type:MIME-Version:Message-ID; b=cg4P5FBYO6KDkGYeYtaEp0wsFdHG7DGD99gjDWNtFv+TrM4m3s2kmwsjq9HEUCEqQMKohOny6eYmk4s4GR0zFP/KUi9+ZRxqMplpXPj4JVnpxQx/AJcjS+iM066PqKgal2z9R/tsItBA7nQuGHUE3utSgJVc0WKhJIM39XlGh8c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=RNv25rh5; arc=none smtp.client-ip=220.197.31.3 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="RNv25rh5" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=Date:From:To:Subject:Content-Type:MIME-Version: Message-ID; bh=D6uWziG+lgdgpLtMcbOSPZAGmmkhOHvBN4q4YiTEeyQ=; b=R Nv25rh51tlRTfr5lFuBUrqpBAW37Jt0j7Z29yu86OKVlEuIeTeVI0zGsp1bEhSrF JoKvI8AFldBIy+FXdeYbanLK26KcxQieMB5+f1N9WevaLDWbOj+cRpkbJjv5jZqL EDrPMicCvh6heXn7BntvypIObtl6rOX25dCUjCGhqk= Received: from luckd0g$163.com ( [183.205.138.18] ) by ajax-webmail-wmsvr-40-127 (Coremail) ; Wed, 11 Mar 2026 15:55:29 +0800 (CST) Date: Wed, 11 Mar 2026 15:55:29 +0800 (CST) From: "Jianzhou Zhao" 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 X-Priority: 3 X-Mailer: Coremail Webmail Server Version 2023.4-cmXT build 20251222(83accb85) Copyright (c) 2002-2026 www.mailtech.cn 163com X-NTES-SC: AL_Qu2cAf6auk8p7yeRYekfmU4Rhug7UMO3uf8n24JfPJ9wjA/p2yseUUF9NmPf88CwFTuXvxiGfTNO1/ZAU5Bifrwxk681x6bP9xT+0Wq929cIgQ== Content-Transfer-Encoding: quoted-printable Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-ID: <2b8b707a.6a35.19cdbe4c889.Coremail.luckd0g@163.com> X-Coremail-Locale: zh_CN X-CM-TRANSID: fygvCgDX_4vxH7Fp6b92AA--.39023W X-CM-SenderInfo: poxfyvkqj6il2tof0z/xtbC9hHKVWmxH-HMPQAA3- X-Coremail-Antispam: 1U5529EdanIXcx71UUUUU7vcSsGvfC2KfnxnUU== Content-Type: text/plain; charset="utf-8" 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 th= e VFS subsystem (`fs/namei.c` and `include/linux/dcache.h`). This bug was f= ound by our custom fuzzing tool, RacePilot. The race concerns the `d_flags`= field of a `dentry` structure: `dont_mount()` modifies the flags concurren= tly with lockless RCU path walks checking `d_is_symlink()` inside `step_int= o_slowpath()`. We observed this bug on the Linux kernel version 6.18.0-0869= 1-g2061f18ad76e-dirty. Call Trace & Context =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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-g2061f= 18ad76e-dirty #42 PREEMPT(voluntary)=20 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/= 2014 =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D 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 i= s 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 |=3D DCACHE_CANT_MOUNT; // <-- Modifies d_flags spin_unlock(&dentry->d_lock); } ``` However, another concurrent process resolving paths (e.g., executing `readl= inkat`) 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) =3D=3D DCACHE_SYMLINK_TYPE; } ``` Root Cause Analysis A KCSAN data race arises because one thread configures the internal `d_flag= s` synchronously within a spinlock but without explicit compiler bounds (`W= RITE_ONCE`), while a second thread concurrently navigates the paths. `__d_e= ntry_type` evaluates `dentry->d_flags` via a plain read (`& DCACHE_ENTRY_TY= PE`). Because path lookups are largely optimized locklessly (RCU walks), `d= _flags` bits can fluctuate concurrently. The writer changes `DCACHE_CANT_MO= UNT` bits which inadvertently triggers standard diagnostics against the mas= king 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 shif= t dynamically for a specific live dentry pointer instance. The concurrent m= utation only manipulates disjoint bit ranges (like `DCACHE_CANT_MOUNT`). Ho= wever, the lack of annotations can trigger compiler tearing optimisations o= n architectures with distinct load/store granularities or simply pollute lo= gs with false positive alarms, obscuring valid concurrency issues. Proposed Fix To accurately reflect the RCU memory model design that allows lockless read= s of `d_flags` bits against asynchronous modifiers acting on orthogonal mas= ks, we should decorate the read access in `__d_entry_type` with the `data_r= ace()` marker. ```diff --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -426,7 +426,7 @@ static inline bool d_mountpoint(const struct dentry *de= ntry) */ 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; } =20 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