Re: [PATCH 6.6.y] cxl/port: Fix use after free of parent_port in cxl_detach_ep()

From: Sasha Levin

Date: Mon May 25 2026 - 11:37:28 EST


On Mon, May 25, 2026 at 03:44:54PM +0800, Fang Wang wrote:
> From: Alison Schofield <alison.schofield@xxxxxxxxx>
>
> [ Upstream commit 19d2f0b97a131198efc2c4ca3eb7f980bba8c2b4 ]
>
> @@ -527,6 +527,7 @@ static void cxl_port_release(struct device *dev)
> xa_destroy(&port->dports);
> xa_destroy(&port->regions);
> ida_free(&cxl_port_ida, port->id);
> + put_device(dev->parent);
> kfree(port);
> }
>
> @@ -657,6 +658,7 @@ static struct cxl_port *cxl_port_alloc(struct device *uport_dev,
> struct cxl_port *iter;
>
> dev->parent = &parent_port->dev;
> + get_device(dev->parent);
> port->depth = parent_port->depth + 1;
> port->parent_dport = parent_dport;

This isn't safe as-is for 6.6. Upstream guards the put_device() in
cxl_port_release() with is_cxl_root(port), and only does the matching
get_device() on the child-port path. In 6.6, struct cxl_root does not
exist yet (it was added in v6.8 by commit 26064b3641c4 ("cxl: introduce
cxl_root")) and the is_cxl_root() helper is absent, so dropping the
guard means cxl_port_release() unconditionally puts dev->parent.

cxl_port_alloc() in 6.6 only takes the new get_device(dev->parent) on
the parent_dport != NULL branch; the root-port path still does
`dev->parent = uport_dev` with no matching get. The result is an
unbalanced put on the root port's uport_dev (typically the cxl_acpi
host device) on every cxl_acpi unload, which is a fresh refcount
underflow / UAF on 6.6.

--
Thanks,
Sasha