mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] cxl/port: Fix missing port lock in cxl_dport_remove()
@ 2026-06-05 18:20 Terry Bowman
  2026-06-05 19:51 ` Cheatham, Benjamin
  0 siblings, 1 reply; 2+ messages in thread
From: Terry Bowman @ 2026-06-05 18:20 UTC (permalink / raw)
  To: Davidlohr Bueso, Jonathan Cameron, Dave Jiang, Alison Schofield,
	Vishal Verma, Ira Weiny, Dan Williams,
	PradeepVineshReddy.Kodamati, Benjamin.Cheatham, rrichter
  Cc: Kuppuswamy Sathyanarayanan, Fabio M . De Francesco, Shiju Jose,
	Smita Koralahalli, Li Ming, Tony Luck, linux-cxl, linux-kernel,
	terry.bowman, stable

xa_erase() in cxl_dport_remove() runs without the port device lock,
creating a race with any caller that does xa_load() on port->dports
and then dereferences the returned dport pointer. A concurrent
cxl_dport_remove() can erase and free the dport between the xa_load()
and the caller acquiring the port lock, causing a use-after-free.

For non-root ports the port lock is already held by the caller on two
paths:

1. Driver unbind: devres_release_all() is called from
   __device_release_driver() which holds port->dev.mutex.

2. Dynamic endpoint removal: cxl_detach_ep() takes the port lock
   before calling del_dports() -> del_dport() -> devres_release_group(),
   which synchronously runs cxl_dport_remove().

Use cond_cxl_root_lock/unlock(), which only acquires the port lock when
the port is a root port and the lock is therefore not already held.
This matches the pattern used in __devm_cxl_add_dport() for the same
reason.

Reported-by: Sashiko
Fixes: 391785859e7e ("cxl/port: Move dport tracking to an xarray")
Signed-off-by: Terry Bowman <terry.bowman@amd.com>
---
 drivers/cxl/core/port.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
index 0c5957d1d329..80ce7c4d357c 100644
--- a/drivers/cxl/core/port.c
+++ b/drivers/cxl/core/port.c
@@ -1088,8 +1088,17 @@ static void cxl_dport_remove(void *data)
 	struct cxl_dport *dport = data;
 	struct cxl_port *port = dport->port;
 
+	/*
+	 * For non-root ports the port lock is already held by the caller
+	 * (driver unbind via devres_release_all(), or cxl_detach_ep() via
+	 * devres_release_group()).  Acquiring it again unconditionally would
+	 * deadlock.  Use cond_cxl_root_lock() which only acquires when the
+	 * port is a root port and the lock is therefore not yet held.
+	 */
+	cond_cxl_root_lock(port);
 	port->nr_dports--;
 	xa_erase(&port->dports, (unsigned long) dport->dport_dev);
+	cond_cxl_root_unlock(port);
 	put_device(dport->dport_dev);
 }
 
-- 
2.34.1


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-06-05 19:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-05 18:20 [PATCH] cxl/port: Fix missing port lock in cxl_dport_remove() Terry Bowman
2026-06-05 19:51 ` Cheatham, Benjamin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®