* [syzbot] [dm?] BUG: unable to handle kernel NULL pointer dereference in dm_bufio_client_create @ 2026-11-01 18:25 syzbot 2026-11-02 13:31 ` Mikulas Patocka 2026-11-05 11:38 ` Edward Adam Davis 0 siblings, 2 replies; 4+ messages in thread From: syzbot @ 2026-11-01 18:25 UTC (permalink / raw) To: agk, bmarzins, dm-devel, linux-kernel, mpatocka, snitzer, syzkaller-bugs Hello, syzbot found the following issue on: HEAD commit: abf8c33470f7 Merge tag 'spi-fix-v7.4-merge-window' of git:.. git tree: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux master console output: https://syzkaller.appspot.com/x/log.txt?x=1578f6ea580000 kernel config: https://syzkaller.appspot.com/x/.config?x=b38f05ed2b645c41 dashboard link: https://syzkaller.appspot.com/bug?extid=41e0d7cdfb1ecfc4a007 compiler: arm-linux-gnueabi-gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44 userspace arch: arm syz repro: https://syzkaller.appspot.com/x/repro.syz?x=12fc4be0580000 C reproducer: https://syzkaller.appspot.com/x/repro.c?x=134c528d580000 Downloadable assets: disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/98a89b9f34e4/non_bootable_disk-abf8c334.raw.xz vmlinux: https://storage.googleapis.com/syzbot-assets/dc6a6b2fa900/vmlinux-abf8c334.xz kernel image: https://storage.googleapis.com/syzbot-assets/a24896395af6/zImage-abf8c334.xz AI-generated root cause summary: In drivers/md/dm-thin.c, pool_ctr() attempts to ensure metadata and data devices are distinct by checking strcmp(argv[0], argv[1]), which fails when different path strings resolve to the same device. When the pool is created with read_only mode, dm_get_device() opens the metadata device as read-only, and the subsequent open of the data device as read-write invokes upgrade_mode() in drivers/md/dm-table.c, which frees the old table device via dm_put_table_device(). This leaves metadata_dev as a dangling pointer (use-after-free); when metadata_dev->bdev is subsequently read as NULL from the freed slab entry and passed to dm_bufio_client_create(), dereferencing bdev->bd_dev causes an immediate kernel NULL pointer dereference. full analysis: https://syzkaller.appspot.com/x/ai_root_cause?x=41e0d7cdfb1ecfc4a007 IMPORTANT: if you fix the issue, please add the following tag to the commit: Reported-by: syzbot+41e0d7cdfb1ecfc4a007@syzkaller.appspotmail.com 8<--- cut here --- Unable to handle kernel NULL pointer dereference at virtual address 00000024 when read [00000024] *pgd=86ce2003, *pmd=df568003 Internal error: Oops: 205 [#1] SMP ARM Modules linked in: CPU: 0 UID: 0 PID: 4130 Comm: syz.2.17 Not tainted syzkaller #0 PREEMPT Hardware name: ARM-Versatile Express PC is at dm_bufio_client_create+0x298/0x5fc drivers/md/dm-bufio.c:2585 LR is at __raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:211 [inline] LR is at _raw_spin_unlock_irqrestore+0x30/0x54 kernel/locking/spinlock.c:221 pc : [<812f4044>] lr : [<81c19680>] psr: 60000013 sp : df9f1b30 ip : df9f1aa8 fp : df9f1bd4 r10: 00000000 r9 : df9f1b48 r8 : 837359c4 r7 : 83735984 r6 : 8633b638 r5 : 00000000 r4 : 8633b600 r3 : 00000000 r2 : 00000000 r1 : ffc00000 r0 : 00000000 Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user Control: 30c5387d Table: 86a96cc0 DAC: fffffffd Register r0 information: NULL pointer Register r1 information: non-paged memory Register r2 information: NULL pointer Register r3 information: NULL pointer Register r4 information: slab kmalloc-512 start 8633b600 pointer offset 0 size 512 Register r5 information: NULL pointer Register r6 information: slab kmalloc-512 start 8633b600 pointer offset 56 size 512 Register r7 information: non-slab/vmalloc memory Register r8 information: non-slab/vmalloc memory Register r9 information: 2-page vmalloc region starting at 0xdf9f0000 allocated at kernel_clone+0xc4/0x440 kernel/fork.c:2784 Register r10 information: NULL pointer Register r11 information: 2-page vmalloc region starting at 0xdf9f0000 allocated at kernel_clone+0xc4/0x440 kernel/fork.c:2784 Register r12 information: 2-page vmalloc region starting at 0xdf9f0000 allocated at kernel_clone+0xc4/0x440 kernel/fork.c:2784 Process syz.2.17 (pid: 4130, stack limit = 0xdf9f0000) Stack: (0xdf9f1b30 to 0xdf9f2000) 1b20: 00000001 00000000 00001fff 00000006 1b40: 00000000 00000008 00000008 00000000 00000000 00000000 00000000 00000000 1b60: 00000000 625f6d64 6f696675 6675625f 2d726566 00312d38 00000000 00000000 1b80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1ba0: 00000000 5d3b91d7 80579764 863f8c80 00000000 00001000 00000006 00000000 1bc0: 00000000 00000800 df9f1c0c df9f1bd8 8130d108 812f3db8 8130d020 8130d03c 1be0: 00000000 868f1040 00000000 868f0c00 00000000 00000000 00000000 00000000 1c00: df9f1c34 df9f1c10 81329660 8130d0a4 868f1040 8276076c 826a9678 00000000 1c20: 83735a70 00000000 df9f1cb4 df9f1c38 81322274 813295d4 00000000 00000000 1c40: 835c30a0 863f87c0 8417c000 86852000 83735a60 00000003 863f894c 00000800 1c60: 863f87cc 00000000 00000014 00000000 812e5f44 00000000 00000007 00000000 1c80: 863f8858 5d3b91d7 00000000 863c7180 868f1040 00000000 00000000 00000800 1ca0: 00000000 00000000 df9f1d0c df9f1cb8 812e623c 81321df0 00000008 df9f1d2c 1cc0: 868f1040 00000000 85b2db60 85b2db50 df9f1d0c 00000006 863f8840 5d3b91d7 1ce0: 86852000 0000006f 85b2db38 85b2db60 85b2da00 00000000 85b2dba8 86852000 1d00: df9f1d64 df9f1d10 812ec884 812e60b0 00000800 00000000 85b2db60 85b2da00 1d20: 812eabcc 863c7180 00000000 863c7180 00000000 5d3b91d7 df9f1d54 812ec740 1d40: 85b2da00 200006c0 863f0e80 00000009 000001a8 000001a8 df9f1f04 df9f1d68 1d60: 812eaa04 812ec74c df9f1e74 81ee19d4 8259d20c 8088542c 81ee1718 00000077 1d80: 85b2db31 b5403587 00000000 00000000 00000001 00000000 00000004 00000032 1da0: 00000000 000001a8 00000138 00000001 00000000 00020000 00000000 00000000 1dc0: 0000f800 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1de0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1e00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1e20: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1e40: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1e60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1e80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1ea0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 1ec0: 00000000 00000000 00000000 00000000 00000003 5d3b91d7 df9f1ef4 00000000 1ee0: 863f0e80 c138fd09 200006c0 863f0e80 00000003 84d3be80 df9f1f14 df9f1f08 1f00: 812eaf64 812ea79c df9f1fa4 df9f1f18 805f2e84 812eaf60 df9f1f4c df9f1f28 1f20: 8035d380 8036088c ffffffff 81c0c4c0 df9f1f54 df9f1f40 8025cbac 00000001 1f40: df9f1fa4 df9f1f50 8035dc54 8035d1f8 00000000 00000001 ffffffff 8341a10c 1f60: 00000000 00000000 00000000 00000000 00000000 5d3b91d7 df9f1fac 00000000 1f80: 00000000 00356310 00000036 8020029c 84d3be80 00000036 00000000 df9f1fa8 1fa0: 80200060 805f2c4c 00000000 00000000 00000003 c138fd09 200006c0 00000000 1fc0: 00000000 00000000 00356310 00000036 003562d8 00000000 00000008 00000000 1fe0: 7ecaa7a0 7ecaa790 0001903c 00130cf0 60000010 00000003 00000000 00000000 Call trace: [<812f3dac>] (dm_bufio_client_create) from [<8130d108>] (dm_block_manager_create+0x70/0xb0 drivers/md/persistent-data/dm-block-manager.c:397) r10:00000800 r9:00000000 r8:00000000 r7:00000006 r6:00001000 r5:00000000 r4:863f8c80 [<8130d098>] (dm_block_manager_create) from [<81329660>] (__create_persistent_data_objects drivers/md/dm-thin-metadata.c:791 [inline]) [<8130d098>] (dm_block_manager_create) from [<81329660>] (dm_pool_metadata_open+0x98/0x15c drivers/md/dm-thin-metadata.c:980) r8:00000000 r7:00000000 r6:00000000 r5:00000000 r4:868f0c00 [<813295c8>] (dm_pool_metadata_open) from [<81322274>] (pool_create drivers/md/dm-thin.c:2946 [inline]) [<813295c8>] (dm_pool_metadata_open) from [<81322274>] (__pool_find drivers/md/dm-thin.c:3113 [inline]) [<813295c8>] (dm_pool_metadata_open) from [<81322274>] (pool_ctr+0x490/0xa64 drivers/md/dm-thin.c:3363) r9:00000000 r8:83735a70 r7:00000000 r6:826a9678 r5:8276076c r4:868f1040 [<81321de4>] (pool_ctr) from [<812e623c>] (dm_table_add_target+0x198/0x3bc drivers/md/dm-table.c:749) r10:00000000 r9:00000000 r8:00000800 r7:00000000 r6:00000000 r5:868f1040 r4:863c7180 [<812e60a4>] (dm_table_add_target) from [<812ec884>] (populate_table drivers/md/dm-ioctl.c:1602 [inline]) [<812e60a4>] (dm_table_add_target) from [<812ec884>] (table_load+0x144/0x3d4 drivers/md/dm-ioctl.c:1645) r10:86852000 r9:85b2dba8 r8:00000000 r7:85b2da00 r6:85b2db60 r5:85b2db38 r4:0000006f [<812ec740>] (table_load) from [<812eaa04>] (ctl_ioctl+0x274/0x7c4 drivers/md/dm-ioctl.c:2221) r10:000001a8 r9:000001a8 r8:00000009 r7:863f0e80 r6:200006c0 r5:85b2da00 r4:812ec740 [<812ea790>] (ctl_ioctl) from [<812eaf64>] (dm_ctl_ioctl+0x10/0x14 drivers/md/dm-ioctl.c:2243) r10:84d3be80 r9:00000003 r8:863f0e80 r7:200006c0 r6:c138fd09 r5:863f0e80 r4:00000000 [<812eaf54>] (dm_ctl_ioctl) from [<805f2e84>] (vfs_ioctl fs/ioctl.c:51 [inline]) [<812eaf54>] (dm_ctl_ioctl) from [<805f2e84>] (do_vfs_ioctl fs/ioctl.c:551 [inline]) [<812eaf54>] (dm_ctl_ioctl) from [<805f2e84>] (__do_sys_ioctl fs/ioctl.c:595 [inline]) [<812eaf54>] (dm_ctl_ioctl) from [<805f2e84>] (sys_ioctl+0x244/0xb5c fs/ioctl.c:583) [<805f2c40>] (sys_ioctl) from [<80200060>] (ret_fast_syscall+0x0/0x1c arch/arm/mm/proc-v7.S:67) Exception stack(0xdf9f1fa8 to 0xdf9f1ff0) 1fa0: 00000000 00000000 00000003 c138fd09 200006c0 00000000 1fc0: 00000000 00000000 00356310 00000036 003562d8 00000000 00000008 00000000 1fe0: 7ecaa7a0 7ecaa790 0001903c 00130cf0 r10:00000036 r9:84d3be80 r8:8020029c r7:00000036 r6:00356310 r5:00000000 r4:00000000 Code: e3a05000 e3a01000 e34f1fc0 e1a00005 (e5932024) ---[ end trace 0000000000000000 ]--- ---------------- Code disassembly (best guess): 0: e3a05000 mov r5, #0 4: e3a01000 mov r1, #0 8: e34f1fc0 movt r1, #65472 @ 0xffc0 c: e1a00005 mov r0, r5 * 10: e5932024 ldr r2, [r3, #36] @ 0x24 <-- trapping instruction --- This report is generated by a bot. It may contain errors. See https://goo.gl/tpsmEJ for more information about syzbot. syzbot engineers can be reached at syzkaller@googlegroups.com. syzbot will keep track of this issue. See: https://goo.gl/tpsmEJ#status for how to communicate with syzbot. If the report is already addressed, let syzbot know by replying with: #syz fix: exact-commit-title If you want syzbot to run the reproducer, reply with: #syz test: git://repo/address.git branch-or-commit-hash If you attach or paste a git patch, syzbot will apply it before testing. If you want to overwrite report's subsystems, reply with: #syz set subsystems: new-subsystem (See the list of subsystem names on the web dashboard) If the report is a duplicate of another one, reply with: #syz dup: exact-subject-of-another-report If you want to undo deduplication, reply with: #syz undup ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [syzbot] [dm?] BUG: unable to handle kernel NULL pointer dereference in dm_bufio_client_create 2026-11-01 18:25 [syzbot] [dm?] BUG: unable to handle kernel NULL pointer dereference in dm_bufio_client_create syzbot @ 2026-11-02 13:31 ` Mikulas Patocka 2026-11-05 11:38 ` Edward Adam Davis 1 sibling, 0 replies; 4+ messages in thread From: Mikulas Patocka @ 2026-11-02 13:31 UTC (permalink / raw) To: syzbot; +Cc: agk, bmarzins, dm-devel, linux-kernel, snitzer, syzkaller-bugs On Sun, 1 Nov 2026, syzbot wrote: > Hello, > > syzbot found the following issue on: > > HEAD commit: abf8c33470f7 Merge tag 'spi-fix-v7.4-merge-window' of git:.. > git tree: https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux master > console output: https://syzkaller.appspot.com/x/log.txt?x=1578f6ea580000 > kernel config: https://syzkaller.appspot.com/x/.config?x=b38f05ed2b645c41 > dashboard link: https://syzkaller.appspot.com/bug?extid=41e0d7cdfb1ecfc4a007 > compiler: arm-linux-gnueabi-gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44 > userspace arch: arm > syz repro: https://syzkaller.appspot.com/x/repro.syz?x=12fc4be0580000 > C reproducer: https://syzkaller.appspot.com/x/repro.c?x=134c528d580000 > > Downloadable assets: > disk image (non-bootable): https://storage.googleapis.com/syzbot-assets/98a89b9f34e4/non_bootable_disk-abf8c334.raw.xz > vmlinux: https://storage.googleapis.com/syzbot-assets/dc6a6b2fa900/vmlinux-abf8c334.xz > kernel image: https://storage.googleapis.com/syzbot-assets/a24896395af6/zImage-abf8c334.xz > > AI-generated root cause summary: > In drivers/md/dm-thin.c, pool_ctr() attempts to ensure metadata and data devices > are distinct by checking strcmp(argv[0], argv[1]), which fails when different > path strings resolve to the same device. When the pool is created with read_only > mode, dm_get_device() opens the metadata device as read-only, and the subsequent > open of the data device as read-write invokes upgrade_mode() in > drivers/md/dm-table.c, which frees the old table device via > dm_put_table_device(). This leaves metadata_dev as a dangling pointer > (use-after-free); when metadata_dev->bdev is subsequently read as NULL from the > freed slab entry and passed to dm_bufio_client_create(), dereferencing > bdev->bd_dev causes an immediate kernel NULL pointer dereference. > > full analysis: https://syzkaller.appspot.com/x/ai_root_cause?x=41e0d7cdfb1ecfc4a007 > > IMPORTANT: if you fix the issue, please add the following tag to the commit: > Reported-by: syzbot+41e0d7cdfb1ecfc4a007@syzkaller.appspotmail.com Hi Does this patch fix it? Mikulas From 6eb66b7887fc04b9917b6868ea5361b39db7af07 Mon Sep 17 00:00:00 2001 From: Ming-Hung Tsai <mtsai@redhat.com> Date: Fri, 30 Oct 2026 17:16:18 +0800 Subject: [PATCH 1/2] dm: fix use-after-free when dm_get_device() widens the open mode There's an UAF bug in dm_get_device(): when a table construction calls dm_get_device() on the same device twice with widen access mode (e.g., read-only first then read-write), the second dm_get_device() calls upgrade_mode(), which reopens the device in upgraded mode, making previously returned dm_dev* a stale pointer. Fixing approaches: - Add per-mode views (dm_dev_ref) from a per-device dm_dev_internal to multiple table_devices. - Keep reusing the dm_dev_ref when the requested mode is included, i.e., a read-only reference can reuse the read-write opened device within a table. - Maintain a canonical block_device pointer in dm_dev_internal for handling the DM_TABLE_DEPS ioctl. Also tweak the way of mode sharing check in find_ref() to "(x & mask) == mask". The result stays the same to the previous upgrade_mode() guard "(x | mask) == x". Pros: keep the relationship between dm_dev_internal and table_device: one dm_dev_internal per device, regardless the mode, so the output of DMM_TABLE_DEPS ioctl unchanged. Cons: extra dm_dev_ref allocation. Note that now the table_device's count not necessarily mean the number tables referecing this <dev, mode> pair, since we're allowing multiple references within a table. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --- drivers/md/dm-ioctl.c | 2 +- drivers/md/dm-table.c | 142 +++++++++++++++++++++++------------------- drivers/md/dm.c | 2 +- drivers/md/dm.h | 18 +++++- 4 files changed, 98 insertions(+), 66 deletions(-) diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 8f945f0aeda5..4a7cb0926c17 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1794,7 +1794,7 @@ static void retrieve_deps(struct dm_table *table, deps->count = count; count = 0; list_for_each_entry(dd, dm_table_get_devices(table), list) - deps->dev[count++] = huge_encode_dev(dd->dm_dev->bdev->bd_dev); + deps->dev[count++] = huge_encode_dev(dd->bdev->bd_dev); param->data_size = param->data_start + needed; } diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index a483f49dd4ce..db1ec4ae8e56 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -165,14 +165,16 @@ int dm_table_create(struct dm_table **result, blk_mode_t mode, static void free_devices(struct list_head *devices, struct mapped_device *md) { - struct list_head *tmp, *next; - - list_for_each_safe(tmp, next, devices) { - struct dm_dev_internal *dd = - list_entry(tmp, struct dm_dev_internal, list); - DMWARN("%s: dm_table_destroy: dm_put_device call missing for %s", - dm_device_name(md), dd->dm_dev->name); - dm_put_table_device(md, dd->dm_dev); + struct dm_dev_internal *dd, *dd_next; + struct dm_dev_ref *ref, *ref_next; + + list_for_each_entry_safe(dd, dd_next, devices, list) { + list_for_each_entry_safe(ref, ref_next, &dd->refs, list) { + DMWARN("%s: dm_table_destroy: dm_put_device call missing for %s", + dm_device_name(md), ref->dm_dev->name); + dm_put_table_device(md, ref->dm_dev); + kfree(ref); + } kfree(dd); } } @@ -218,12 +220,27 @@ static struct dm_dev_internal *find_device(struct list_head *l, dev_t dev) struct dm_dev_internal *dd; list_for_each_entry(dd, l, list) - if (dd->dm_dev->bdev->bd_dev == dev) + if (dd->bdev->bd_dev == dev) return dd; return NULL; } +/* + * See if the device is already open with a mode that covers the + * requested one. + */ +static struct dm_dev_ref *find_ref(struct dm_dev_internal *dd, blk_mode_t mode) +{ + struct dm_dev_ref *ref; + + list_for_each_entry(ref, &dd->refs, list) + if ((ref->dm_dev->mode & mode) == mode) + return ref; + + return NULL; +} + /* * If possible, this checks an area of a destination device is invalid. */ @@ -303,31 +320,6 @@ static int device_area_is_invalid(struct dm_target *ti, struct dm_dev *dev, return 0; } -/* - * This upgrades the mode on an already open dm_dev, being - * careful to leave things as they were if we fail to reopen the - * device and not to touch the existing bdev field in case - * it is accessed concurrently. - */ -static int upgrade_mode(struct dm_dev_internal *dd, blk_mode_t new_mode, - struct mapped_device *md) -{ - int r; - struct dm_dev *old_dev, *new_dev; - - old_dev = dd->dm_dev; - - r = dm_get_table_device(md, dd->dm_dev->bdev->bd_dev, - dd->dm_dev->mode | new_mode, &new_dev); - if (r) - return r; - - dd->dm_dev = new_dev; - dm_put_table_device(md, old_dev); - - return 0; -} - /* * Note: the __ref annotation is because this function can call the __init * marked early_lookup_bdev when called during early boot code from dm-init.c. @@ -360,7 +352,9 @@ EXPORT_SYMBOL(dm_devt_from_path); /* * Add a device to the list, or just increment the usage count if - * it's already present. + * it's already present with a mode that covers the requested one. + * Otherwise open the device again with the requested mode, so the + * dm_devs returned earlier stay valid. */ int dm_get_device(struct dm_target *ti, const char *path, blk_mode_t mode, struct dm_dev **result) @@ -368,6 +362,7 @@ int dm_get_device(struct dm_target *ti, const char *path, blk_mode_t mode, int r; dev_t dev; struct dm_dev_internal *dd; + struct dm_dev_ref *ref; struct dm_table *t = ti->table; BUG_ON(!t); @@ -380,30 +375,46 @@ int dm_get_device(struct dm_target *ti, const char *path, blk_mode_t mode, return -EINVAL; dd = find_device(&t->devices, dev); - if (!dd) { + if (dd) { + ref = find_ref(dd, mode); + if (ref) { + refcount_inc(&ref->count); + goto out; + } + } else { dd = kmalloc_obj(*dd); if (!dd) return -ENOMEM; + INIT_LIST_HEAD(&dd->refs); + } - r = dm_get_table_device(t->md, dev, mode, &dd->dm_dev); - if (r) { - kfree(dd); - return r; - } + ref = kmalloc_obj(*ref); + if (!ref) { + r = -ENOMEM; + goto bad; + } - refcount_set(&dd->count, 1); - list_add(&dd->list, &t->devices); - goto out; + r = dm_get_table_device(t->md, dev, mode, &ref->dm_dev); + if (r) { + kfree(ref); + goto bad; + } + refcount_set(&ref->count, 1); - } else if (dd->dm_dev->mode != (mode | dd->dm_dev->mode)) { - r = upgrade_mode(dd, mode, t->md); - if (r) - return r; + /* A device in the list always has at least one ref */ + if (list_empty(&dd->refs)) { + dd->bdev = ref->dm_dev->bdev; + list_add(&dd->list, &t->devices); } - refcount_inc(&dd->count); + list_add_tail(&ref->list, &dd->refs); out: - *result = dd->dm_dev; + *result = ref->dm_dev; return 0; + +bad: + if (list_empty(&dd->refs)) + kfree(dd); + return r; } EXPORT_SYMBOL(dm_get_device); @@ -453,23 +464,28 @@ static int dm_set_device_limits(struct dm_target *ti, struct dm_dev *dev, */ void dm_put_device(struct dm_target *ti, struct dm_dev *d) { - int found = 0; struct list_head *devices = &ti->table->devices; struct dm_dev_internal *dd; + struct dm_dev_ref *ref; - list_for_each_entry(dd, devices, list) { - if (dd->dm_dev == d) { - found = 1; - break; - } - } - if (!found) { - DMERR("%s: device %s not in table devices list", - dm_device_name(ti->table->md), d->name); + list_for_each_entry(dd, devices, list) + list_for_each_entry(ref, &dd->refs, list) + if (ref->dm_dev == d) + goto found; + + DMERR("%s: device %s not in table devices list", + dm_device_name(ti->table->md), d->name); + return; + +found: + if (!refcount_dec_and_test(&ref->count)) return; - } - if (refcount_dec_and_test(&dd->count)) { - dm_put_table_device(ti->table->md, d); + + dm_put_table_device(ti->table->md, d); + list_del(&ref->list); + kfree(ref); + + if (list_empty(&dd->refs)) { list_del(&dd->list); kfree(dd); } diff --git a/drivers/md/dm.c b/drivers/md/dm.c index eb9e32995b79..1fff84b3f869 100644 --- a/drivers/md/dm.c +++ b/drivers/md/dm.c @@ -1588,7 +1588,7 @@ static void __send_empty_flush(struct clone_info *ci) */ clone = alloc_tio(ci, NULL, 0, &len, GFP_NOIO); atomic_add(1, &ci->io->io_count); - bio_set_dev(clone, dd->dm_dev->bdev); + bio_set_dev(clone, dd->bdev); clone->bi_end_io = clone_endio; dm_submit_bio_remap(clone, NULL); } diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 7a795979ec72..34f58060243f 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -37,10 +37,26 @@ /* * List of devices that a metadevice uses and should open/close. + * There is one dm_dev_internal per device. It holds one dm_dev_ref + * for each mode that the targets opened the device with. */ struct dm_dev_internal { struct list_head list; - refcount_t count; + struct block_device *bdev; + struct list_head refs; +}; + +/* + * One open of a device with one mode, shared by the targets of a table. + * dm_get_device() reuses a dm_dev_ref whose mode covers the requested + * mode, and adds a new one only when none does. So the dm_dev_refs of + * a device have different modes, and a table holds each table_device + * at most once. table_device->count is still the number of tables that + * use the table_device. + */ +struct dm_dev_ref { + struct list_head list; + refcount_t count; /* dm_get_device() calls that returned dm_dev */ struct dm_dev *dm_dev; }; -- 2.49.0 ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [syzbot] [dm?] BUG: unable to handle kernel NULL pointer dereference in dm_bufio_client_create 2026-11-01 18:25 [syzbot] [dm?] BUG: unable to handle kernel NULL pointer dereference in dm_bufio_client_create syzbot 2026-11-02 13:31 ` Mikulas Patocka @ 2026-11-05 11:38 ` Edward Adam Davis 2026-11-05 12:14 ` syzbot 1 sibling, 1 reply; 4+ messages in thread From: Edward Adam Davis @ 2026-11-05 11:38 UTC (permalink / raw) To: syzbot+41e0d7cdfb1ecfc4a007; +Cc: linux-kernel, syzkaller-bugs From: Edward Aadm Davis <eadavis@sina.com> #syz test: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git abf8c33470f7 diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c index 358ed77ffb2b..f15d5815ffab 100644 --- a/drivers/md/dm-thin.c +++ b/drivers/md/dm-thin.c @@ -3292,6 +3292,7 @@ static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv) dm_block_t low_water_blocks; struct dm_dev *metadata_dev; blk_mode_t metadata_mode; + struct block_device *md_bdev, *data_bdev; /* * FIXME Remove validation from scope of lock. @@ -3331,6 +3332,7 @@ static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->error = "Error opening metadata block device"; goto out_unlock; } + md_bdev = metadata_dev->bdev; warn_if_metadata_device_too_big(metadata_dev->bdev); r = dm_get_device(ti, argv[1], BLK_OPEN_READ | BLK_OPEN_WRITE, &data_dev); @@ -3338,6 +3340,9 @@ static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv) ti->error = "Error getting data device"; goto out_metadata; } + data_bdev = data_dev->bdev; + if (md_bdev == data_bdev) + metadata_dev = data_dev; if (kstrtoul(argv[2], 10, &block_size) || !block_size || block_size < DATA_DEV_BLOCK_SIZE_MIN_SECTORS || @@ -3428,7 +3433,8 @@ static int pool_ctr(struct dm_target *ti, unsigned int argc, char **argv) out: dm_put_device(ti, data_dev); out_metadata: - dm_put_device(ti, metadata_dev); + if (md_bdev != data_bdev) + dm_put_device(ti, metadata_dev); out_unlock: mutex_unlock(&dm_thin_pool_table.mutex); ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [syzbot] [dm?] BUG: unable to handle kernel NULL pointer dereference in dm_bufio_client_create 2026-11-05 11:38 ` Edward Adam Davis @ 2026-11-05 12:14 ` syzbot 0 siblings, 0 replies; 4+ messages in thread From: syzbot @ 2026-11-05 12:14 UTC (permalink / raw) To: eadavis, linux-kernel, syzkaller-bugs Hello, syzbot has tested the proposed patch and the reproducer did not trigger any issue: Reported-by: syzbot+41e0d7cdfb1ecfc4a007@syzkaller.appspotmail.com Tested-by: syzbot+41e0d7cdfb1ecfc4a007@syzkaller.appspotmail.com Tested on: commit: abf8c334 Merge tag 'spi-fix-v7.4-merge-window' of git:.. git tree: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git console output: https://syzkaller.appspot.com/x/log.txt?x=106751ed580000 kernel config: https://syzkaller.appspot.com/x/.config?x=b38f05ed2b645c41 dashboard link: https://syzkaller.appspot.com/bug?extid=41e0d7cdfb1ecfc4a007 compiler: arm-linux-gnueabi-gcc (Debian 14.2.0-19) 14.2.0, GNU ld (GNU Binutils for Debian) 2.44 userspace arch: arm patch: https://syzkaller.appspot.com/x/patch.diff?x=1228c98d580000 Note: testing is done by a robot and is best-effort only. ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-11-05 12:14 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-11-01 18:25 [syzbot] [dm?] BUG: unable to handle kernel NULL pointer dereference in dm_bufio_client_create syzbot 2026-11-02 13:31 ` Mikulas Patocka 2026-11-05 11:38 ` Edward Adam Davis 2026-11-05 12:14 ` syzbot
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®