syzbot
WARNING in r1buf_pool_alloc
Status:
upstream: reported C repro on 2026/11/15 17:41
Subsystems:
raid
Labels:
prio:low
[Documentation on labels]
Reported-by: syzbot+c0e700c08ee88f60e54d@syzkaller.appspotmail.com
First crash: 4h00m, last: 3h40m
✨ AI-generated root cause summary:
When configuring a software RAID1 array via the SET_ARRAY_INFO ioctl, md_set_array_info() in drivers/md/md.c does not validate the user-supplied info->raid_disks value. When an array is initialized with an excessively large raid_disks count (e.g. 0x8002 / 32,770), the resync initialization in raid1_sync_request() invokes r1buf_pool_alloc() in drivers/md/raid1.c to preallocate mempool buffers. r1buf_pool_alloc() attempts to allocate an array of struct resync_pages via kmalloc_objs(..., conf->raid_disks * 2, ...) exceeding KMALLOC_MAX_SIZE (4 MiB), which triggers the WARN_ON_ONCE_GFP check in ___kmalloc_large_node() in mm/slub.c.
▶
▼
✨ Full AI root cause analysis
Root Cause Analysis
1. Involved Components and Files
2. Mechanism and Trigger Path
-
Unchecked raid_disks Setting:
A privileged user (CAP_SYS_ADMIN) issues the SET_ARRAY_INFO ioctl on an uninitialized MD device (/dev/md0). In drivers/md/md.c:md_set_array_info(), the kernel sets mddev->raid_disks directly from user input (info->raid_disks) without verifying that info->raid_disks is within sane or allocatable bounds:
mddev->raid_disks = info->raid_disks;
In the reproducer, info->raid_disks is configured to 0x8002 (32,770) with info->not_persistent = 0x2000.
-
Array Initialization and Sync Thread Kickoff:
When the RUN_ARRAY ioctl is subsequently called (md_run() -> raid1_run() -> setup_conf()), conf->mirrors is allocated with kzalloc(array3_size(sizeof(struct raid1_info), mddev->raid_disks, 2), GFP_KERNEL) (~2 MiB) and conf->r1bio_pool is created with elements of size offsetof(struct r1bio, bios[mddev->raid_disks * 2]) (~512 KiB). Both allocations are below KMALLOC_MAX_SIZE (4 MiB on x86-64), so setup_conf() succeeds and the MD resync thread (md_do_sync()) is spawned.
-
Excessive Allocation in Resync Buffer Pool:
Once md_do_sync() executes, it calls pers->sync_request (raid1_sync_request()). Because conf->r1buf_pool is not yet initialized, it calls init_resync(conf):
buffs = RESYNC_WINDOW / RESYNC_BLOCK_SIZE;
return mempool_init(&conf->r1buf_pool, buffs, r1buf_pool_alloc,
r1buf_pool_free, conf);
mempool_init() invokes r1buf_pool_alloc() in drivers/md/raid1.c:
rps = kmalloc_objs(struct resync_pages, conf->raid_disks * 2, gfp_flags);
sizeof(struct resync_pages) is 136 bytes (void *raid_bio + 16 page pointers pages[16]).
conf->raid_disks * 2 is 32770 * 2 = 65540 (0x10004).
- The total requested size is
65540 * 136 = 8,913,440 bytes (0x880220 bytes, ~8.5 MiB).
-
Triggering the Warning:
Because 0x880220 exceeds KMALLOC_MAX_SIZE (0x400000 / 4 MiB), ___kmalloc_large_node() in mm/slub.c detects size > KMALLOC_MAX_SIZE with gfp_flags lacking __GFP_NOWARN, triggering the warning:
if (WARN_ON_ONCE_GFP(size > KMALLOC_MAX_SIZE, flags))
return NULL;
After the warning is emitted, ___kmalloc_large_node() returns NULL. r1buf_pool_alloc() safely aborts via goto out_free_r1bio; and returns NULL, which causes mempool_init_node() to clean up and return -ENOMEM. raid1_sync_request() returns 0, and md_do_sync() catches this condition (sectors == 0), sets MD_RECOVERY_INTR, and gracefully terminates the resync loop without crashing or corrupting memory.
Sample crash report:
md: resync of RAID array md0
------------[ cut here ]------------
1
WARNING: mm/slub.c:5459 at ___kmalloc_large_node+0x132/0x170 mm/slub.c:5459, CPU#2: md0_resync/6011
Modules linked in:
CPU: 2 UID: 0 PID: 6011 Comm: md0_resync Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
RIP: 0010:___kmalloc_large_node+0x132/0x170 mm/slub.c:5459
Code: db 0f 85 66 ff ff ff 45 31 e4 eb cb 48 81 ff 00 00 40 00 0f 86 07 ff ff ff 80 3d 51 7d d6 0f 00 75 0b c6 05 48 7d d6 0f 01 90 <0f> 0b 90 48 83 c4 08 31 c0 5b 5d 41 5c 41 5d 41 5e c3 cc cc cc cc
RSP: 0018:ffffc90003cf7608 EFLAGS: 00010246
RAX: ffffffff88996c0e RBX: 0000000000880220 RCX: 0000000000000000
RDX: 00000000ffffffff RSI: 0000000000000cc0 RDI: 0000000000880220
RBP: 0000000000000cc0 R08: 0000000000000000 R09: 0000000000000000
R10: ffffed100c6b000e R11: 0000000000000000 R12: 0000000000000cc0
R13: 00000000ffffffff R14: 0000000000880220 R15: ffffed10048c1435
FS: 0000000000000000(0000) GS:ffff8880d466c000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 000055559223fa28 CR3: 000000000fd98000 CR4: 0000000000352ef0
Call Trace:
<TASK>
__kmalloc_large_node_noprof+0x1c/0x70 mm/slub.c:5502
__do_kmalloc_node mm/slub.c:5519 [inline]
__kmalloc_noprof+0x5a3/0x840 mm/slub.c:5556
_kmalloc_noprof include/linux/slab.h:995 [inline]
r1buf_pool_alloc+0xfe/0xd90 drivers/md/raid1.c:181
mempool_init_node+0x2f7/0x6f0 mm/mempool.c:272
mempool_init_noprof+0x3a/0x50 mm/mempool.c:302
init_resync drivers/md/raid1.c:2684 [inline]
raid1_sync_request+0x1f5e/0x2ff0 drivers/md/raid1.c:2734
md_do_sync.cold+0xf79/0x2946 drivers/md/md.c:9962
md_thread+0x550/0x5d0 drivers/md/md.c:8732
kthread+0x373/0x450 kernel/kthread.c:436
ret_from_fork+0x730/0xd60 arch/x86/kernel/process.c:158
ret_from_fork_asm+0x1a/0x30 arch/x86/entry/entry_64.S:245
</TASK>
* Struck through repros no longer work on HEAD.