From: Sasha Levin <sashal@kernel.org>
To: Dingisoul <dingiso.kernel@gmail.com>, nvdimm@lists.linux.dev
Subject: Re: [BUG]: KASAN: slab-use-after-free in nd_async_device_register on commit 3609fa95fb0f2c1b099e69e56634edb8fc03f87c
Date: Wed, 4 Mar 2026 08:05:54 -0500 [thread overview]
Message-ID: <20260304130555.76151-1-sashal@kernel.org> (raw)
In-Reply-To: <8855544b-be9e-4153-aa55-0bc328b13733@gmail.com>
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: stable@vger.kernel.org
prev parent reply other threads:[~2026-03-04 13:05 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-04 3:35 [BUG]: KASAN: slab-use-after-free in nd_async_device_register on commit 3609fa95fb0f2c1b099e69e56634edb8fc03f87c Dingisoul
2026-03-04 13:05 ` Sasha Levin [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260304130555.76151-1-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=dingiso.kernel@gmail.com \
--cc=nvdimm@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox