BUG: KCSAN: data-race in ext4_fill_super / super_s_dev_test
Subject: [BUG] fs: KCSAN: data-race in ext4_fill_super / super_s_dev_test
Dear Maintainers,
We are writing to report a KCSAN-detected data race vulnerability within the VFS and ext4 subsystem. This bug was found by our custom fuzzing tool, RacePilot. The race occurs during the filesystem mount procedure when ext4_check_journal_data_mode (via ext4_fill_super) sets SB_I_CGROUPWB in sb->s_iflags without strict synchronization, while super_s_dev_test contemporaneously checks for the SB_I_RETIRED bit in the same s_iflags variable while iterating over fs_supers. We observed this bug on the Linux kernel version 6.18.0-08691-g2061f18ad76e-dirty.
Call Trace & Context
==================================================================
BUG: KCSAN: data-race in ext4_fill_super / super_s_dev_test
write to 0xffff88802f427058 of 8 bytes by task 25360 on cpu 1:
ext4_check_journal_data_mode fs/ext4/super.c:5021 [inline] __ext4_fill_super fs/ext4/super.c:5364 [inline] ext4_fill_super+0x1308/0x7590 fs/ext4/super.c:5777 get_tree_bdev_flags+0x256/0x370 fs/super.c:1699 get_tree_bdev+0x1f/0x30 fs/super.c:1722 ext4_get_tree+0x1c/0x30 fs/ext4/super.c:5809 ... __x64_sys_mount+0x1d7/0x210 fs/namespace.c:4201
read to 0xffff88802f427058 of 8 bytes by task 25340 on cpu 0:
super_s_dev_test+0x1c/0xa0 fs/super.c:1386 sget_fc+0x13a/0x6c0 fs/super.c:755 sget_dev fs/super.c:1413 [inline] get_tree_bdev_flags+0x124/0x370 fs/super.c:1685 get_tree_bdev+0x1f/0x30 fs/super.c:1722 ext4_get_tree+0x1c/0x30 fs/ext4/super.c:5809 ... __x64_sys_mount+0x1d7/0x210 fs/namespace.c:4201
value changed: 0x0000000000000000 -> 0x0000000000004001
Reported by Kernel Concurrency Sanitizer on:
CPU: 0 UID: 0 PID: 25340 Comm: syz.1.1392 Not tainted 6.18.0-08691-g2061f18ad76e-dirty #44 PREEMPT(voluntary) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.15.0-1 04/01/2014 ==================================================================
Execution Flow & Code Context
During the mounting phase of a new ext4 instance, the system allocates a superblock and inserts it into the fs_supers list globally (handled in sget_fc()). Later, the ext4_fill_super() phase modifies sb->s_iflags configuration properties directly. This happens without acquiring the sb_lock which covers list traversals. Concretely, in fs/ext4/super.c:
```c
// fs/ext4/super.c
static int ext4_check_journal_data_mode(struct super_block *sb)
{
...
} else {
sb->s_iflags |= SB_I_CGROUPWB; // <-- Plain concurrent write
}
return 0;
}
```Whenever another concurrent mount thread (or internal iteration) searches through existing superblocks for the block device via sget_dev(), it iterates over the linked structures calling super_s_dev_test(). super_s_dev_test inspects s->s_iflags to verify the retired status.
```c
// fs/super.c
static int super_s_dev_test(struct super_block *s, struct fs_context *fc)
{
return !(s->s_iflags & SB_I_RETIRED) && // <-- Plain concurrent read
s->s_dev == *(dev_t *)fc->sget_key;
}
```Root Cause Analysis
A KCSAN data race arises because one thread configures the internal superblock identifier flags concurrently while a secondary thread traverses the global list of superblocks scanning for active block devices. s->s_iflags acts as shared state globally visible through the filesystem subsystem list from the point it gets listed in sget_fc. The read evaluation of s_iflags overlaps with the logical OR operation, establishing an undocumented race. Unfortunately, we were unable to generate a reproducer for this bug.
Potential Impact
This data race is functionally extremely minor or mostly benign since the read only targets the SB_I_RETIRED bit, while the write sets the SB_I_CGROUPWB bit. However, the lack of annotations can trigger aggressive compiler tearing implementations across architecture layouts, risking transient false SB_I_RETIRED positives causing unexpected remount disconnections. It generates excessive fuzzing alerts that obscure critical concurrency flaws.
Proposed Fix
We can wrap the evaluation condition in super_s_dev_test() explicitly to advise KCSAN and suppress the diagnostic alert effectively, affirming the concurrent access is tracked by the developers and functionally verified.
```diff
--- a/fs/super.c
+++ b/fs/super.c
@@ -1383,7 +1383,7 @@ static int super_s_dev_set(struct super_block *s, struct fs_context *fc)
static int super_s_dev_test(struct super_block *s, struct fs_context *fc)
{
- return !(s->s_iflags & SB_I_RETIRED) &&
+ return !(data_race(s->s_iflags) & SB_I_RETIRED) &&
s->s_dev == *(dev_t *)fc->sget_key;
}
```We would be highly honored if this could be of any help.
Best regards,
RacePilot Team