This response was AI-generated by bug-bot. The analysis may contain errors — 
please verify independently.

## Bug Summary

**KASAN slab-use-after-free** in `nd_async_device_register()` 
(`drivers/nvdimm/bus.c:495`), introduced by commit `b6eae0f61db2` in v4.20-rc1 
(September 2018). The bug triggers when `device_add()` fails (e.g., due to 
memory allocation failure in `device_private_init()`), causing the device to be 
freed before its `parent` pointer is accessed.

Here is the formatted reply:

---

### 1. Bug Summary
Use-after-free in `nd_async_device_register()` in the nvdimm subsystem, 
triggered when `device_add()` fails. Severity: crash (KASAN splat / potential 
data corruption). Affected subsystem: libnvdimm (drivers/nvdimm/bus.c).

### 2. Stack Trace Analysis
The KASAN report shows the crash at `nd_async_device_register` 
(drivers/nvdimm/bus.c:495), in workqueue/async context. The device was freed by 
the same task via `put_device` -> `kobject_put` -> `device_release` -> `kfree`.

### 3. Root Cause
Commit `b6eae0f61db2` added `get_device(dev->parent)` / 
`put_device(dev->parent)` to hold a parent reference during async init, but the 
`put_device(dev->parent)` dereferences `dev->parent` **after** 
`put_device(dev)` may have freed `dev`.

### 4. Affected Versions
v4.20 onward (all stable trees that backported `b6eae0f61db2`).

### 5. Fix
Save `dev->parent` before the `put_device(dev)` calls.

### 6. Prior Discussions
No prior reports found on lore.kernel.org.

### 7. Suggested Actions
- Alexander Duyck authored the original commit and should review.
- Dan Williams, Vishal Verma, Dave Jiang, Ira Weiny as nvdimm maintainers.

---

Here is the final output:

```
### 1. Bug Summary

This is a use-after-free bug in nd_async_device_register() in the nvdimm
subsystem (drivers/nvdimm/bus.c). When device_add() fails due to a
memory allocation failure in device_private_init(), the subsequent
put_device(dev) calls drop the device refcount to zero, freeing the
device. The code then dereferences dev->parent on the freed object,
triggering a KASAN slab-use-after-free. Severity: crash / potential
memory corruption.

### 2. Stack Trace Analysis

Decoded stack trace from the KASAN report:

  dump_stack_lvl (lib/dump_stack.c:122)
  print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
  kasan_report (mm/kasan/report.c:597)
  nd_async_device_register (drivers/nvdimm/bus.c:495)
  async_run_entry_fn (kernel/async.c:131)
  process_scheduled_works (kernel/workqueue.c:3340)
  worker_thread (kernel/workqueue.c:3422)
  kthread (kernel/kthread.c:465)
  ret_from_fork (arch/x86/kernel/process.c:164)
  ret_from_fork_asm (arch/x86/entry/entry_64.S:256)

Free trace (same task 131):
  kasan_save_track (mm/kasan/common.c:58)
  kasan_save_free_info (mm/kasan/generic.c:587)
  __kasan_slab_free (mm/kasan/common.c:287)
  kfree (mm/slub.c:6878)
  device_release (drivers/gpu/drm/vkms/vkms_configfs.c:745)
  kobject_put (lib/kobject.c:737)
  nd_async_device_register (drivers/nvdimm/bus.c:495)

The crash occurs in async/workqueue context (kworker/u9:3). The crash
point is at drivers/nvdimm/bus.c:495, which is the dereference of
dev->parent after put_device(dev) has already freed the device object.
The free trace confirms the device was freed by the same call chain
through put_device(dev) -> kobject_put -> device_release -> kfree.

### 3. Root Cause Analysis

The bug is in nd_async_device_register() at drivers/nvdimm/bus.c:486-497.

The reference counting flow when device_add() fails:

  __nd_device_register():
    get_device(dev->parent)   -- parent refcount +1
    get_device(dev)           -- dev refcount +1 (now 2)

  nd_async_device_register():
    device_add(dev):
      get_device(dev)         -- dev refcount +1 (now 3)
      device_private_init()   -- fails (ENOMEM)
      put_device(dev)         -- dev refcount -1 (now 2)
      returns error
    put_device(dev)           -- dev refcount -1 (now 1) [line 492]
    put_device(dev)           -- dev refcount -1 (now 0, dev FREED) [line 494]
    dev->parent               -- USE-AFTER-FREE [line 495]
    put_device(dev->parent)   -- [line 496]

Commit b6eae0f61db2 ("libnvdimm: Hold reference on parent while
scheduling async init") added the get_device(dev->parent) in
__nd_device_register() and the corresponding put_device(dev->parent)
in nd_async_device_register(). However, the put_device(dev->parent)
dereferences dev->parent AFTER put_device(dev) may have freed dev.

The fix is straightforward: save dev->parent in a local variable before
the put_device(dev) calls that can free the device:

  static void nd_async_device_register(void *d, async_cookie_t cookie)
  {
      struct device *dev = d;
      struct device *parent = dev->parent;

      if (device_add(dev) != 0) {
          dev_err(dev, "%s: failed\n", __func__);
          put_device(dev);
      }
      put_device(dev);
      if (parent)
          put_device(parent);
  }

### 4. Affected Versions

The bug was introduced by commit b6eae0f61db2 ("libnvdimm: Hold
reference on parent while scheduling async init"), first included in
v4.20-rc1 (September 2018). This is a regression from v4.19.

The commit was also backported to multiple stable trees, so all
maintained stable kernels from v4.20 onward are affected.

### 5. Relevant Commits and Fixes

Introducing commit:
  b6eae0f61db2 ("libnvdimm: Hold reference on parent while scheduling async 
init")

The original code that b6eae0f61db2 was fixing:
  4d88a97aa9e8 ("libnvdimm, nvdimm: dimm driver and base libnvdimm 
device-driver infrastructure")

No existing fix was found in mainline or stable trees as of
v6.19-rc4 (commit 3609fa95fb0f).

### 6. Prior Discussions

No prior reports of this specific bug were found on lore.kernel.org.
No related mailing list discussions, proposed patches, or review threads
were identified.

### 7. Suggested Actions

1. The fix is to save dev->parent in a local variable before the
   put_device(dev) calls, as shown in the root cause analysis above.

2. Adding Alexander Duyck who authored commit b6eae0f61db2 that
   introduced this bug.

3. Adding Dan Williams, Vishal Verma, Dave Jiang, and Ira Weiny as
   nvdimm subsystem maintainers.

4. Once fixed, the patch should be tagged:
     Fixes: b6eae0f61db2 ("libnvdimm: Hold reference on parent while scheduling 
async init")
     Cc: [email protected]


Reply via email to