Hi Kernel maintainers,
Our tool found a new kernel bug KASAN: slab-use-after-free in
nd_async_device_register on commit 3609fa95fb0f2c1b099e69e56634edb8fc03f87c
(Sun Jan 4 16:57:47 2026).
Please see the details below.
We observe such an error-triggering execution path in function
nd_async_device_register.
static void nd_async_device_register(void *d, async_cookie_t cookie)
{
struct device *dev = d;
// 1. The device refcount is 2.
if (device_add(dev) != 0) {
dev_err(dev, "%s: failed\n", __func__);
put_device(dev);// 6. Refcount drops to 1.
}
put_device(dev); // 7. Refcount drops to 0, dev is freed.
if (dev->parent) // 8. Accesses the freed "dev",
// triggering the use-after-free.
put_device(dev->parent);
}
int device_add(struct device *dev)
{
...
int error = -EINVAL;
...
dev = get_device(dev); // 2. Refcount increases to 3.
if (!dev)
goto done;
if (!dev->p) {
error = device_private_init(dev); // 3. Fails inside.
if (error)
goto done;
}
...
done:
put_device(dev); // 5. Refcount drops to 2.
return error;
}
static int device_private_init(struct device *dev)
{
dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL);// 4. Allocation
fail.
if (!dev->p)
return -ENOMEM;
dev->p->device = dev;
klist_init(&dev->p->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->p->deferred_probe);
return 0;
}
By allowing the allocation to fail inside device_private_init(),
the bug can be stably triggered in QEMU, generating the following KASAN
report:
[T131] ==================================================================
[T131] BUG: KASAN: slab-use-after-free in nd_async_device_register
(drivers/nvdim
m/bus.c:495)
[T131] Read of size 8 at addr ffff88810d2a4858 by task kworker/u9:3/131
[T131]
[T131] CPU: 0 UID: 0 PID: 131 Comm: kworker/u9:3 Not tainted
6.19.0-rc4-g3609fa95
fb0f-dirty #35 PREEMPT(full)
[T131] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.15.0-1 04/01
/2014
[T131] Workqueue: async async_run_entry_fn
[T131] Call Trace:
[T131] <TASK>
[T131] dump_stack_lvl (lib/dump_stack.c:122)
[T131] print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
[T131] kasan_report (mm/kasan/report.c:597)
[T131] nd_async_device_register (drivers/nvdimm/bus.c:495)
[T131] async_run_entry_fn (./arch/x86/include/asm/jump_label.h:37
kernel/async.c
:131)
[T131] process_scheduled_works (kernel/workqueue.c:?
kernel/workqueue.c:3340)
[T131] worker_thread (./include/linux/list.h:381 kernel/workqueue.c:946
kernel/w
orkqueue.c:3422)
[T131] kthread (kernel/kthread.c:465)
[T131] ret_from_fork (arch/x86/kernel/process.c:164)
[T131] ret_from_fork_asm (arch/x86/entry/entry_64.S:256)
[T131] </TASK>
[T131]
[T131] Freed by task 131:
[T131] kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78)
[T131] kasan_save_free_info (mm/kasan/generic.c:587)
[T131] __kasan_slab_free (mm/kasan/common.c:287)
[T131] kfree (mm/slub.c:6670 mm/slub.c:6878)
[T131] device_release (drivers/gpu/drm/vkms/vkms_configfs.c:745)
[T131] kobject_put (lib/kobject.c:? lib/kobject.c:720
./include/linux/kref.h:65
lib/kobject.c:737)
[T131] nd_async_device_register (drivers/nvdimm/bus.c:495)
[T131] async_run_entry_fn (./arch/x86/include/asm/jump_label.h:37
kernel/async.c
:131)
[T131] process_scheduled_works (kernel/workqueue.c:?
kernel/workqueue.c:3340)
[T131] worker_thread (./include/linux/list.h:381 kernel/workqueue.c:946
kernel/w
orkqueue.c:3422)
[T131] kthread (kernel/kthread.c:465)
[T131] ret_from_fork (arch/x86/kernel/process.c:164)
[T131] ret_from_fork_asm (arch/x86/entry/entry_64.S:256)
[T131]
[T131] The buggy address belongs to the object at ffff88810d2a4800
[T131] which belongs to the cache kmalloc-1k of size 1024
[T131] The buggy address is located 88 bytes inside of
[T131] freed 1024-byte region [ffff88810d2a4800, ffff88810d2a4c00)