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)

Reply via email to