* [PATCH v3] cxl/core: Fix dport use-after-free via the einj_inject debugfs file
@ 2026-08-28 7:47 Guixin Liu
2026-08-29 0:31 ` Alison Schofield
0 siblings, 1 reply; 2+ messages in thread
From: Guixin Liu @ 2026-08-28 7:47 UTC (permalink / raw)
To: Davidlohr Bueso, Jonathan Cameron, Dave Jiang, Alison Schofield,
Vishal Verma, Dan Williams, Ira Weiny, Li Ming
Cc: linux-cxl
The per-dport einj_inject debugfs file retains a pointer to the
'struct cxl_dport', but its lifetime is not tied to the dport. Unbinding
the dport host frees the dport and leaves einj_inject behind, so writing
the file dereferences freed memory:
BUG: KASAN: slab-use-after-free in cxl_einj_inject+0xa1/0xf0 [cxl_core]
Read of size 1 at addr ffff88810880ac90 by task bash/1690
cxl_einj_inject+0xa1/0xf0 [cxl_core]
debugfs_attr_write+0x61/0xb0
full_proxy_write+0xfc/0x1c0
vfs_write+0x1d4/0xe60
Allocated by task 213:
__devm_cxl_add_dport+0x1e1/0x14d0 [cxl_core]
cxl_port_add_dport+0xd6/0x200 [cxl_port]
Freed by task 1622:
release_nodes+0xfa/0x2c0
devres_release_all+0x113/0x1a0
device_unbind_cleanup+0x76/0x260
unbind_store+0xde/0x100
The stale directory also prevents recreation on rebind.
Remove the per-dport debugfs directory when the dport host is released.
Found by code inspection, then reproduced on a QEMU CXL topology with
KASAN (the einj_cxl_is_initialized() guard had to be forced open, as
QEMU emits no EINJ table). Unpatched, writing the leftover file after
unbind gives the splat above, and rebind hits "already exists in
'cxl'". Patched, the directory goes away with the dport and rebind
recreates a working einj_inject.
Fixes: 8039804cfa73 ("cxl/core: Add CXL EINJ debugfs files")
Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
Reviewed-by: Richard Cheng <icheng@nvidia.com>
Reviewed-by: Li Ming <ming.li@zohomail.com>
---
This was patch 3/8 of the "cxl: Assorted fixes" series [1]. Per review
feedback that series is not being reworked as a whole; the fixes are resent
individually instead.
Exact steps behind the testing paragraph above, on a QEMU topology with two
root ports under a host bridge port plus a switch, KASAN enabled:
# find the per-dport dir and the cxl_port that hosts the dport
find /sys/kernel/debug/cxl -name einj_inject
ls -d /sys/bus/cxl/devices/port1/dport*
echo port1 > /sys/bus/cxl/drivers/cxl_port/unbind
# unpatched: /sys/bus/cxl/devices/port1/dport0 is gone but
# /sys/kernel/debug/cxl/0000:34:00.0/einj_inject remains
# patched: /sys/kernel/debug/cxl/0000:34:00.0 is gone too
echo 0x1 > /sys/kernel/debug/cxl/0000:34:00.0/einj_inject
# unpatched: the KASAN splat quoted in the commit message
# patched: no such file; no KASAN report for the whole boot
# 0x1 is deliberately not a CXL error type, so both inject paths return
# -EINVAL from einj_is_cxl_error_type() after the dport read
echo port1 > /sys/bus/cxl/drivers/cxl_port/bind
for m in mem0 mem1 mem2; do echo $m > /sys/bus/cxl/drivers/cxl_mem/bind; done
# unpatched: debugfs: '0000:34:00.0' already exists in 'cxl'
# and a write to the surviving file still faults, at a different
# address than the new dport, i.e. still the old freed one
# patched: both einj_inject files recreated, write returns -EINVAL
v2 -> v3:
- no code change; drivers/cxl/core/port.c is byte-identical to v2, so
Richard's and Li Ming's Reviewed-by from v2 are carried forward. Only the
commit message differs, please shout if you would rather re-review.
- cut the commit message down to the problem, its impact and the fix, and
quote the KASAN splat rather than narrating the code (Alison Schofield)
- say how the issue was found and what was actually tested
(Alison Schofield)
v1 -> v2:
- do not propagate the devm_add_action_or_reset() failure out of
cxl_debugfs_create_dport_dir(); a missing debugfs directory must not fail
the dport addition (Li Ming)
- rebase onto cxl/next
- rewrite the commit message to describe the behaviour rather than narrate
the code change (Alison Schofield)
[1] https://lore.kernel.org/linux-cxl/20260811113608.2815625-1-kanie@linux.alibaba.com/
drivers/cxl/core/port.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 625e4aa427db..62a9c2038d1f 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -814,6 +814,11 @@ static int cxl_einj_inject(void *data, u64 type)
DEFINE_DEBUGFS_ATTRIBUTE(cxl_einj_inject_fops, NULL, cxl_einj_inject,
"0x%llx\n");
+static void remove_debugfs(void *dentry)
+{
+ debugfs_remove_recursive(dentry);
+}
+
static void cxl_debugfs_create_dport_dir(struct cxl_dport *dport)
{
struct cxl_port *parent = parent_port_of(dport->port);
@@ -834,6 +839,8 @@ static void cxl_debugfs_create_dport_dir(struct cxl_dport *dport)
debugfs_create_file("einj_inject", 0200, dir, dport,
&cxl_einj_inject_fops);
+
+ devm_add_action_or_reset(dport_to_host(dport), remove_debugfs, dir);
}
static int cxl_port_add(struct cxl_port *port,
base-commit: 7098e9cd98a05c0c5de2fae0c2465f9d966fdd07
--
2.43.7
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v3] cxl/core: Fix dport use-after-free via the einj_inject debugfs file
2026-08-28 7:47 [PATCH v3] cxl/core: Fix dport use-after-free via the einj_inject debugfs file Guixin Liu
@ 2026-08-29 0:31 ` Alison Schofield
0 siblings, 0 replies; 2+ messages in thread
From: Alison Schofield @ 2026-08-29 0:31 UTC (permalink / raw)
To: Guixin Liu
Cc: Davidlohr Bueso, Jonathan Cameron, Dave Jiang, Vishal Verma,
Dan Williams, Ira Weiny, Li Ming, linux-cxl
On Fri, Aug 28, 2026 at 03:47:52PM +0800, Guixin Liu wrote:
> The per-dport einj_inject debugfs file retains a pointer to the
> 'struct cxl_dport', but its lifetime is not tied to the dport. Unbinding
> the dport host frees the dport and leaves einj_inject behind, so writing
> the file dereferences freed memory:
>
> BUG: KASAN: slab-use-after-free in cxl_einj_inject+0xa1/0xf0 [cxl_core]
> Read of size 1 at addr ffff88810880ac90 by task bash/1690
> cxl_einj_inject+0xa1/0xf0 [cxl_core]
> debugfs_attr_write+0x61/0xb0
> full_proxy_write+0xfc/0x1c0
> vfs_write+0x1d4/0xe60
> Allocated by task 213:
> __devm_cxl_add_dport+0x1e1/0x14d0 [cxl_core]
> cxl_port_add_dport+0xd6/0x200 [cxl_port]
> Freed by task 1622:
> release_nodes+0xfa/0x2c0
> devres_release_all+0x113/0x1a0
> device_unbind_cleanup+0x76/0x260
> unbind_store+0xde/0x100
>
> The stale directory also prevents recreation on rebind.
>
> Remove the per-dport debugfs directory when the dport host is released.
>
> Found by code inspection, then reproduced on a QEMU CXL topology with
> KASAN (the einj_cxl_is_initialized() guard had to be forced open, as
> QEMU emits no EINJ table). Unpatched, writing the leftover file after
> unbind gives the splat above, and rebind hits "already exists in
> 'cxl'". Patched, the directory goes away with the dport and rebind
> recreates a working einj_inject.
>
> Fixes: 8039804cfa73 ("cxl/core: Add CXL EINJ debugfs files")
> Signed-off-by: Guixin Liu <kanie@linux.alibaba.com>
> Reviewed-by: Richard Cheng <icheng@nvidia.com>
> Reviewed-by: Li Ming <ming.li@zohomail.com>
Thanks for the changelog updatges Guixin.
DaveJ - KASAN trace could be left out upon applying.
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-08-29 0:31 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-28 7:47 [PATCH v3] cxl/core: Fix dport use-after-free via the einj_inject debugfs file Guixin Liu
2026-08-29 0:31 ` Alison Schofield
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox