Re: [PATCH 3/8] cxl/core: Fix dport use-after-free via the einj_inject debugfs file

Li Ming <[email protected]>
Newsgroups org.kernel.vger.linux-cxl
Message-ID <[email protected]>
在 2026/8/11 19:36, Guixin Liu 写道:
> cxl_debugfs_create_dport_dir() creates a debugfs directory holding an
> "einj_inject" file whose i_private is the 'struct cxl_dport', but it
> discards the returned dentry and registers no cleanup. The dport is freed
> by free_dport() when the devres group of its host device is released,
> while the debugfs nodes live until the cxl_core module is unloaded
> (debugfs_remove_recursive() in cxl_core_exit()).
>
> So after unbinding the dport's host, e.g. unbinding the host bridge port
> or the ACPI0017 root, writing to
>
>    /sys/kernel/debug/cxl/<dport_dev>/einj_inject
>
> calls cxl_einj_inject() on freed memory and dereferences dport->rch and
> dport->dport_dev.
>
> The leaked directory is also named after the dport device, so re-adding the
> same dport (bind after unbind) hits an existing name, debugfs creation
> fails, and error injection stays broken for that dport for the rest of the
> module's lifetime.
>
> Save the dentry and drop the whole directory via a devm action on the same
> host device. The action is registered inside the dport devres group and
> after free_dport(), so it runs before the dport is freed. Propagate the
> failure to __devm_cxl_add_dport() rather than continuing with a dport that
> has a dangling debugfs node.
>
> Fixes: 8039804cfa73 ("cxl/core: Add CXL EINJ debugfs files")
> Signed-off-by: Guixin Liu <[email protected]>
> ---
>   drivers/cxl/core/port.c | 18 ++++++++++++++----
>   1 file changed, 14 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/cxl/core/port.c b/drivers/cxl/core/port.c
> index 1215ee4f4035..76bda54ed986 100644
> --- a/drivers/cxl/core/port.c
> +++ b/drivers/cxl/core/port.c
> @@ -813,13 +813,18 @@ 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 cxl_debugfs_create_dport_dir(struct cxl_dport *dport)
> +static void remove_debugfs(void *dentry)
> +{
> +	debugfs_remove_recursive(dentry);
> +}
> +
> +static int cxl_debugfs_create_dport_dir(struct cxl_dport *dport)
>   {
>   	struct cxl_port *parent = parent_port_of(dport->port);
>   	struct dentry *dir;
>   
>   	if (!einj_cxl_is_initialized())
> -		return;
> +		return 0;
>   
>   	/*
>   	 * Protocol error injection is only available for CXL 2.0+ root ports
> @@ -827,12 +832,15 @@ static void cxl_debugfs_create_dport_dir(struct cxl_dport *dport)
>   	 */
>   	if (!dport->rch &&
>   	    !(dev_is_pci(dport->dport_dev) && parent && is_cxl_root(parent)))
> -		return;
> +		return 0;
>   
>   	dir = cxl_debugfs_create_dir(dev_name(dport->dport_dev));
>   
>   	debugfs_create_file("einj_inject", 0200, dir, dport,
>   			    &cxl_einj_inject_fops);
> +
> +	return devm_add_action_or_reset(dport_to_host(dport), remove_debugfs,
> +					dir);

I think we don't need to worry about devm_add_action_or_reset() failing, 
missing this debugfs directory seems like acceptable, but the failure 
cases of this devm_add_action_or_reset() will cause dport addition failure.

So I think just like below devm_cxl_dport_ras_setup(), do not check the 
return value of the function.

>   }
>   
>   static int cxl_port_add(struct cxl_port *port,
> @@ -1240,7 +1248,9 @@ __devm_cxl_add_dport(struct cxl_port *port, struct device *dport_dev,
>   	if (dev_is_pci(dport_dev))
>   		dport->link_latency = cxl_pci_get_latency(to_pci_dev(dport_dev));
>   
> -	cxl_debugfs_create_dport_dir(dport);
> +	rc = cxl_debugfs_create_dport_dir(dport);
> +	if (rc)
> +		return ERR_PTR(rc);
>   
>   	if (!dport->rch)
>   		devm_cxl_dport_ras_setup(dport);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.