WARNING in bd_unlink_disk_holder

Status: moderation: reported syz repro on 2026/11/05 19:35
Subsystems: block
Labels: prio:low
[Documentation on labels]
Reported-by: syzbot+c73578fe2ee27895ab8f@syzkaller.appspotmail.com
First crash: 2h49m, last: 1h26m
✨ AI-generated root cause summary:

In drivers/md/md.c:bind_rdev_to_array(), an rdev is added to mddev->disks and bd_link_disk_holder() is called to create the holder/slave relationship without checking its return value. If bd_link_disk_holder() fails (for example, returning -EINVAL when an array's own block device or partition is imported into itself, or on memory/sysfs failures), no bd_holder_disk entry is added to disk->slave_bdevs, yet the device remains bound to the array. When the array is subsequently stopped via do_md_stop() -> export_array() -> md_kick_rdev_from_array(), bd_unlink_disk_holder() is called and bd_find_holder_disk() returns NULL, triggering WARN_ON_ONCE(holder == NULL) at block/holder.c:147.

▶ ▼ ✨ Full AI root cause analysis
Based on kernel commit b0958b1397fb:

Root Cause Analysis

1. Mechanism and Crash Site

The warning is triggered in block/holder.c:147 inside bd_unlink_disk_holder():

void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk)
{
	struct bd_holder_disk *holder;
...
	mutex_lock(&blk_holder_mutex);
	holder = bd_find_holder_disk(bdev, disk);
	if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) {
...

bd_unlink_disk_holder() expects that every unlinking operation corresponds to a previously established holder relationship recorded in disk->slave_bdevs. When bd_find_holder_disk() traverses disk->slave_bdevs and cannot find an entry whose holder_dir matches bdev->bd_holder_dir, it returns NULL, triggering WARN_ON_ONCE(holder == NULL).

The call trace demonstrates this occurring when stopping an MD array (STOP_ARRAY ioctl):

do_md_stop() -> export_array() -> md_kick_rdev_from_array() -> bd_unlink_disk_holder()

For each struct md_rdev *rdev remaining in mddev->disks, export_array() calls md_kick_rdev_from_array(rdev), which in turn calls bd_unlink_disk_holder(rdev->bdev, rdev->mddev->gendisk).


2. Defect in drivers/md/md.c

In the MD subsystem, an rdev is added to mddev->disks exclusively by bind_rdev_to_array():

static int bind_rdev_to_array(struct md_rdev *rdev, struct mddev *mddev)
{
...
	list_add_rcu(&rdev->same_set, &mddev->disks);
	bd_link_disk_holder(rdev->bdev, mddev->gendisk);

	return 0;
...
}

There are two key flaws in this implementation:

  1. Unchecked Return Value of bd_link_disk_holder(): bind_rdev_to_array() calls bd_link_disk_holder() without checking its return value and returns 0 (success). If bd_link_disk_holder() fails, the rdev remains attached to mddev->disks, but no struct bd_holder_disk is allocated or linked to mddev->gendisk->slave_bdevs.
  2. Missing Invariant Check on Self-Referencing Disks: bind_rdev_to_array() does not check whether rdev->bdev->bd_disk == mddev->gendisk. Inside bd_link_disk_holder() (block/holder.c:70):
    if (bdev->bd_disk == disk)
        return -EINVAL;
    
    A block device cannot hold itself or its own partitions.

3. How the Bug is Triggered

  1. An MD array (e.g., /dev/md4) is started with non-zero capacity (as indicated by the log: md4: detected capacity change from 4096 to 0).
  2. An ioctl such as ADD_NEW_DISK or HOT_ADD_DISK is executed, passing the device number (dev_t) of /dev/md4 itself (or one of its partitions).
  3. md_import_device() opens the device via bdev_file_open_by_dev(). Since the device is active and has non-zero size, it successfully creates the struct md_rdev.
  4. bind_rdev_to_array() is called. It checks for duplicate dev_t entries among existing rdevs via find_rdev(), which passes if /dev/md4 was not previously in the array.
  5. bind_rdev_to_array() places rdev onto &mddev->disks via list_add_rcu(), and calls bd_link_disk_holder(rdev->bdev, mddev->gendisk).
  6. Because rdev->bdev->bd_disk == mddev->gendisk, bd_link_disk_holder() returns -EINVAL without allocating or linking a bd_holder_disk. (Similarly, this occurs if bd_link_disk_holder() fails due to -ENODEV, -ENOMEM, or sysfs link creation failure).
  7. bind_rdev_to_array() ignores the -EINVAL return code and returns 0.
  8. Later, userspace stops the array via STOP_ARRAY (do_md_stop(mddev, 0)). export_array() iterates over mddev->disks and invokes md_kick_rdev_from_array(), which calls bd_unlink_disk_holder(rdev->bdev, mddev->gendisk).
  9. bd_find_holder_disk() returns NULL, triggering the warning at block/holder.c:147.
▶ ▼ ✨ AI Jobs (1)
ID Workflow Result Correct Bug Created Started Finished Revision
00df2403 assessment-security DenialOfService: ❌ Exploitable: ❌ FilesystemTrigger: ❌ FuzzingArtifact: ❌ MemoryCorruption: ❌ NetworkNeedsSetup: ❌ NetworkTrigger: ❌ PeripheralTrigger: ❌ RemoteTrigger: ❌ Unprivileged: ❌ UserNamespace: ❌ VMGuestTrigger: ❌ VMHostTrigger: ❌ ❓ WARNING in bd_unlink_disk_holder 2026/11/05 18:31 2026/11/05 18:31 2026/11/05 19:27 5cecaf1f

Sample crash report:
md: md3 stopped.
------------[ cut here ]------------
WARNING: block/holder.c:147 at bd_find_holder_disk block/holder.c:18 [inline], CPU#1: syz.3.20/5100
WARNING: block/holder.c:147 at bd_unlink_disk_holder+0xd8/0x2d4 block/holder.c:146, CPU#1: syz.3.20/5100
Modules linked in:
CPU: 1 UID: 0 PID: 5100 Comm: syz.3.20 Not tainted syzkaller #0 PREEMPT 
Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 08/14/2026
pstate: 83400005 (Nzcv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
pc : bd_unlink_disk_holder+0xd8/0x2d4 block/holder.c:18
lr : bd_find_holder_disk block/holder.c:18 [inline]
lr : bd_unlink_disk_holder+0xd8/0x2d4 block/holder.c:146
sp : ffff8000984577e0
x29: ffff8000984577e0 x28: 1fffe0001e3c2b06 x27: ffff0000d50be3d0
x26: 1fffe00018292d16 x25: 1fffe0001aa17c79 x24: ffff0000d50be3c8
x23: dfff800000000000 x22: ffff0000c14968b0 x21: ffff0000c1496780
x20: ffff0000d50be000 x19: ffff0000d50be3d0 x18: 00000000ffffffff
x17: ffff0001acebb3a7 x16: ffff0000d9043b14 x15: ffff800080d532c4
x14: 00000000005bd313 x13: 0000000000000001 x12: 0000000000000003
x11: 0000000000000000 x10: 0000000000000001 x9 : 0000000000000000
x8 : 0000000000000000 x7 : ffff8000818fb144 x6 : 0000000000000000
x5 : 0000000000000000 x4 : 0000000000000001 x3 : ffff80008046bc7c
x2 : 0000000000000001 x1 : ffff0000d9043b00 x0 : 0000000000000000
Call trace:
 bd_find_holder_disk block/holder.c:18 [inline] (P)
 bd_unlink_disk_holder+0xd8/0x2d4 block/holder.c:146 (P)
 md_kick_rdev_from_array+0x8c/0x324 drivers/md/md.c:2683
 export_array drivers/md/md.c:2714 [inline]
 do_md_stop+0x708/0xe6c drivers/md/md.c:7252
 md_ioctl+0x14ec/0x23e4 drivers/md/md.c:8462
 blkdev_ioctl+0x574/0x904 block/ioctl.c:798
 vfs_ioctl fs/ioctl.c:51 [inline]
 __do_sys_ioctl fs/ioctl.c:597 [inline]
 __se_sys_ioctl fs/ioctl.c:583 [inline]
 __arm64_sys_ioctl+0x154/0x1cc fs/ioctl.c:583
 __invoke_syscall arch/arm64/kernel/syscall.c:35 [inline]
 invoke_syscall+0x98/0x244 arch/arm64/kernel/syscall.c:49
 el0_svc_common+0xec/0x23c arch/arm64/kernel/syscall.c:121
 do_el0_svc+0x4c/0x5c arch/arm64/kernel/syscall.c:140
 el0_svc+0x60/0x1d8 arch/arm64/kernel/entry-common.c:796
 el0t_64_sync_handler+0x44/0x104 arch/arm64/kernel/entry-common.c:815
 el0t_64_sync+0x198/0x19c arch/arm64/kernel/entry.S:606
irq event stamp: 1514
hardirqs last  enabled at (1513): [<ffff8000804a3fb4>] vprintk_store+0x924/0xb94 kernel/printk/printk.c:2385
hardirqs last disabled at (1514): [<ffff800086953878>] el1_brk64+0x20/0x54 arch/arm64/kernel/entry-common.c:483
softirqs last  enabled at (1364): [<ffff8000801373b8>] local_bh_enable include/linux/bottom_half.h:33 [inline]
softirqs last  enabled at (1364): [<ffff8000801373b8>] put_cpu_fpsimd_context arch/arm64/kernel/fpsimd.c:251 [inline]
softirqs last  enabled at (1364): [<ffff8000801373b8>] do_sve_acc+0x3ac/0x56c arch/arm64/kernel/fpsimd.c:1333
softirqs last disabled at (1362): [<ffff800080137110>] local_bh_disable include/linux/bottom_half.h:20 [inline]
softirqs last disabled at (1362): [<ffff800080137110>] get_cpu_fpsimd_context arch/arm64/kernel/fpsimd.c:234 [inline]
softirqs last disabled at (1362): [<ffff800080137110>] do_sve_acc+0x104/0x56c arch/arm64/kernel/fpsimd.c:1308
---[ end trace 0000000000000000 ]---

Crashes (2):
Time Kernel Commit Syzkaller Config Log Report Syz repro C repro VM info Assets (help?) Manager Title
2026/11/05 19:15 git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci b0958b1397fb 5cecaf1f .config console log report syz / log [disk image] [vmlinux] [kernel image] ci-upstream-gce-arm64 WARNING in bd_unlink_disk_holder
2026/11/05 17:52 git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git for-kernelci b0958b1397fb 5cecaf1f .config console log report info [disk image] [vmlinux] [kernel image] ci-upstream-gce-arm64 WARNING in bd_unlink_disk_holder
* Struck through repros no longer work on HEAD.