syzbot
kernel BUG in sysfs_break_active_protection
Status:
upstream: reported C repro on 2026/11/01 00:24
Subsystems:
driver-core
fs
Labels:
prio:normal
[Documentation on labels]
Reported-by: syzbot+dcad997ed2b5bd95cc5e@syzkaller.appspotmail.com
First crash: 4d16h, last: 21h57m
✨ AI-generated root cause summary:
In md_attr_store(), writing "clear" to array_state invokes sysfs_break_active_protection() prior to acquiring all_mddevs_lock and validating the device via mddev_get(). Since sysfs writes only hold kernfs active references rather than a kobject reference, a concurrent deletion or teardown of the mddev can drop the final reference on mddev->kobj, reducing kobj->kref to zero before kernfs removal drains pending active accesses. Calling sysfs_break_active_protection() then executes kobject_get() on the zero-refcount object, triggering a refcount use-after-free saturation/BUG and potentially corrupting memory or crashing the kernel.
▶
▼
✨ Full AI root cause analysis
Root Cause Analysis
1. Functions, Structs, and Files Involved
drivers/md/md.c:
md_attr_store(): sysfs write callback for mddev attributes.
mddev_delayed_delete() / __mddev_put() / mddev_put(): cleanup path that invokes kobject_put(&mddev->kobj) when mddev->active drops to zero.
struct mddev: contains embedded struct kobject kobj and flags like MD_DELETED.
fs/sysfs/file.c:
sysfs_break_active_protection(): breaks active kernfs protection; unconditionally calls kobject_get(kobj).
lib/kobject.c:
kobject_get() -> kref_get() -> refcount_inc(): attempts to increment kobj->kref.refcount.
kobject_put() -> kref_put() -> kobject_release() / kobject_cleanup(): drops the last refcount and tears down sysfs files via __kobject_del().
2. Triggering Mechanism and Lifecycle Invariant Violation
In sysfs/kernfs, file operations (e.g. kernfs_fop_write_iter() -> sysfs_kf_write()) acquire an active reference on the kernfs_node (kernfs_get_active_of()), but they do not take a reference on the associated struct kobject (mddev->kobj). Instead, kernfs relies on kobject_del() / sysfs_remove_dir() invoking kernfs_drain() during teardown to wait for all in-flight file operations to finish before releasing resources.
In drivers/md/md.c:
- When an
mddev is torn down or stopped, mddev_put() drops mddev->active to 0. __mddev_put() queues mddev->del_work (mddev_delayed_delete), which calls kobject_put(&mddev->kobj).
kobject_put() invokes kref_put(&kobj->kref, kobject_release), which decrements kobj->kref.refcount from 1 to 0 before entering kobject_cleanup().
- In
kobject_cleanup(), __kobject_del() is called to remove the sysfs directory and drain active kernfs references.
- However, if a user write of
"clear" to /sys/block/mdX/md/array_state executes concurrently, it can successfully acquire the kernfs active reference (kernfs_get_active_of()) right before __kobject_del() drains the node.
- In
md_attr_store() (drivers/md/md.c:6166-6176):
if (entry->store == array_state_store && cmd_match(page, "clear"))
kn = sysfs_break_active_protection(kobj, attr);
spin_lock(&all_mddevs_lock);
if (!mddev_get(mddev)) {
...
sysfs_break_active_protection(kobj, attr) is invoked before taking all_mddevs_lock and checking mddev_get(mddev) (which checks MD_DELETED and returns NULL).
sysfs_break_active_protection() calls kobject_get(kobj), which executes refcount_inc(&kobj->kref.refcount). Because the refcount is already 0, this violates the refcount invariant that an increment cannot occur on an object with refcount 0, triggering:
refcount_t: addition on 0; use-after-free. -> kernel BUG at lib/refcount.c:34!
3. Runtime Consequences in Production Kernels
MemoryCorruption (true):
An addition on a refcount of 0 signifies that kobject_cleanup() is running or about to run concurrently. In kobject_cleanup(), md_kobj_release() -> put_disk() -> md_free_disk() frees struct mddev via kfree(mddev). Concurrently incrementing the refcount on a dying object and continuing to access mddev or subsequently calling kobject_put() / sysfs_unbreak_active_protection() leads to use-after-free, double-free, and refcount corruption.
RawDenialOfService (true):
On systems built with CONFIG_BUG_ON_DATA_CORRUPTION=y, the kernel hits an unrecoverable BUG() in refcount_warn_saturate(). On systems without it, use-after-free on struct mddev / kobj leads to kernel crash / panic or memory corruption when accessing the freed device.
InfoLeak ("none"):
The defect does not read or expose uninitialized or out-of-bounds kernel memory contents to userspace.
IsNetCandidate (false):
The defect is in the block MD RAID subsystem and sysfs file operations, unrelated to networking or network protocols.
IsKVMCandidate (false):
The defect is unrelated to virtualization, KVM, hypervisors, or virtio.
▶
▼
Last patch testing requests (2)
Sample crash report:
refcount_t: addition on 0; use-after-free.
------------[ cut here ]------------
kernel BUG at lib/refcount.c:34!
Oops: invalid opcode: 0000 [#1] SMP KASAN PTI
CPU: 1 UID: 0 PID: 6056 Comm: syz-executor398 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 10/15/2026
RIP: 0010:refcount_warn_saturate+0xf0/0x110 lib/refcount.c:34
Code: 80 c1 03 38 c1 0f 8c 6a ff ff ff 4c 89 f7 e8 e7 44 51 fd e9 5d ff ff ff e8 dd 23 da fc 48 c7 c7 e0 a3 8c 8c e8 a1 d1 38 fc 90 <0f> 0b e8 c9 23 da fc 48 c7 c7 60 a4 8c 8c e8 8d d1 38 fc 90 0f 0b
RSP: 0018:ffffc90002e5fb78 EFLAGS: 00010246
RAX: 000000000000002a RBX: 0000000000000002 RCX: 4550039d880cf800
RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000
RBP: 0000000000000000 R08: ffffffff9014c84b R09: 1ffffffff2029909
R10: dffffc0000000000 R11: fffffbfff202990a R12: dffffc0000000000
R13: 1ffffffff22654c6 R14: ffff88807c40e128 R15: dffffc0000000000
FS: 00007f63dcdeb6c0(0000) GS:ffff88812350b000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055b9ba686138 CR3: 0000000074ef4000 CR4: 00000000003526f0
Call Trace:
<TASK>
__refcount_add include/linux/refcount.h:-1 [inline]
__refcount_inc include/linux/refcount.h:366 [inline]
refcount_inc include/linux/refcount.h:383 [inline]
kref_get include/linux/kref.h:45 [inline]
kobject_get+0xfa/0x120 lib/kobject.c:643
sysfs_break_active_protection+0x28/0xa0 fs/sysfs/file.c:471
md_attr_store+0x28f/0x640 drivers/md/md.c:6167
kernfs_fop_write_iter+0x3a4/0x540 fs/kernfs/file.c:345
new_sync_write fs/read_write.c:595 [inline]
vfs_write+0x612/0xba0 fs/read_write.c:687
ksys_pwrite64 fs/read_write.c:1504 [inline]
__do_sys_pwrite64 fs/read_write.c:1512 [inline]
__se_sys_pwrite64 fs/read_write.c:1509 [inline]
__x64_sys_pwrite64+0x210/0x2c0 fs/read_write.c:1509
do_syscall_x64 arch/x86/entry/syscall_64.c:61 [inline]
do_syscall_64+0x166/0x520 arch/x86/entry/syscall_64.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f63de64ba9e
Code: 08 0f 85 f5 e2 ff ff 49 89 fb 48 89 f0 48 89 d7 48 89 ce 4c 89 c2 4d 89 ca 4c 8b 44 24 08 4c 8b 4c 24 10 4c 89 5c 24 08 0f 05 <c3> 90 41 57 41 56 4d 89 c6 41 55 4d 89 cd 41 54 55 53 48 83 ec 08
RSP: 002b:00007f63dcdeb0f8 EFLAGS: 00000246 ORIG_RAX: 0000000000000012
RAX: ffffffffffffffda RBX: 00007f63dcdeb6c0 RCX: 00007f63de64ba9e
RDX: 0000000000000005 RSI: 00007f63de69003a RDI: 0000000000000006
RBP: 0000000000000006 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 00007f63de69003a
R13: 0000000000000003 R14: 00007f63de6c3100 R15: 00007f63de6c4b4c
</TASK>
Modules linked in:
---[ end trace 0000000000000000 ]---
RIP: 0010:refcount_warn_saturate+0xf0/0x110 lib/refcount.c:34
Code: 80 c1 03 38 c1 0f 8c 6a ff ff ff 4c 89 f7 e8 e7 44 51 fd e9 5d ff ff ff e8 dd 23 da fc 48 c7 c7 e0 a3 8c 8c e8 a1 d1 38 fc 90 <0f> 0b e8 c9 23 da fc 48 c7 c7 60 a4 8c 8c e8 8d d1 38 fc 90 0f 0b
RSP: 0018:ffffc90002e5fb78 EFLAGS: 00010246
RAX: 000000000000002a RBX: 0000000000000002 RCX: 4550039d880cf800
RDX: 0000000000000000 RSI: 0000000000000001 RDI: 0000000000000000
RBP: 0000000000000000 R08: ffffffff9014c84b R09: 1ffffffff2029909
R10: dffffc0000000000 R11: fffffbfff202990a R12: dffffc0000000000
R13: 1ffffffff22654c6 R14: ffff88807c40e128 R15: dffffc0000000000
FS: 00007f63dcdeb6c0(0000) GS:ffff88812350b000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f94a870e7d0 CR3: 0000000074ef4000 CR4: 00000000003526f0
* Struck through repros no longer work on HEAD.