All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Peng Fan (OSS)" <peng.fan@oss.nxp.com>
Cc: Frank.Li@kernel.org, imx@lists.linux.dev
Subject: Re: [PATCH] driver core: hand off fwnode ownership when shared fwnode owner is rejected
Date: Mon, 28 Sep 2026 12:04:14 +0000	[thread overview]
Message-ID: <20260928120414.CB8CD1F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260928-driver-core-v1-1-0846bb8e0f32@nxp.com>

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] driver core: UAF due to race transferring fwnode to tearing-down sibling
- [High] driver core: UAF/NULL dereference due to lockless fwnode->dev access
- [Medium] driver core: race between probe failure and sibling binding orphans fwnode
--

commit a697546921283509d4dd33e97eef3ff8dcaff551
Author: Peng Fan <peng.fan@nxp.com>

driver core: hand off fwnode ownership when shared fwnode owner is rejected

This commit addresses boot failures when a shared fwnode owner fails to
probe, leading to unresolved consumer links. It introduces logic to transfer
fwnode ownership to a bound sibling when the original owner is rejected.

> diff --git a/drivers/base/core.c b/drivers/base/core.c
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
[ ... ]
> @@ -1376,6 +1376,20 @@ void device_links_driver_bound(struct device *dev)
>  	struct device_link *link, *ln;
>  	LIST_HEAD(sync_list);
>  
> +	/*
> +	 * Multiple devices may share the same fwnode (e.g. the SCMI bus
> +	 * creates several devices per protocol node).  The first one
> +	 * registered owns the fwnode; if that owner's driver is rejected
> +	 * it relinquishes ownership (fwnode->dev == NULL, see
> +	 * fw_devlink_release_shared_fwnode()).  If the owning device has
> +	 * no driver at all (driver never compiled / loaded as module), it
> +	 * will never bind, so it is safe to take over.  Re-acquire the
> +	 * fwnode here so the purge/pickup still happens.
> +	 */
> +	if (dev->fwnode && (!dev->fwnode->dev ||
> +	    (dev->fwnode->dev != dev && !dev->fwnode->dev->driver)))

[Severity: High]
Is it safe to dereference the dev->fwnode->dev->driver pointer locklessly
here?

If the owning device is concurrently unregistered via device_del() and cleared
from fwnode->dev, the compiler might reload the weak pointer as NULL before
dereferencing ->driver, leading to a NULL pointer dereference.

Alternatively, it could dereference ->driver on a pointer to a newly freed
device object, resulting in a use-after-free.

[Severity: Medium]
Could this condition incorrectly rely on ->driver to deduce if the owner is
still active, missing the window where the owner is tearing down but hasn't
cleared the pointer yet?

If Sibling 1 (the fwnode owner) fails probe, it calls
fw_devlink_release_shared_fwnode(). However, dev->driver is still set at this
stage.

If Sibling 2 finishes probing and evaluates this condition concurrently,
it will see Sibling 1 as the owner with a populated ->driver pointer and skip
claiming ownership. Sibling 1 then clears the pointer to NULL. Neither sibling
performs the required purge and pickup routines, leaving consumers to defer
indefinitely.

> +		dev->fwnode->dev = dev;
> +
[ ... ]
> @@ -1474,6 +1489,54 @@ void device_links_driver_bound(struct device *dev)
>  	device_links_flush_sync_list(&sync_list, dev);
>  }
>  
> +static int fwnode_shared_bound_match(struct device *dev, const void *data)
[ ... ]
> +void fw_devlink_release_shared_fwnode(struct device *dev)
> +{
> +	struct device *sibling;
> +
> +	if (!dev->fwnode || dev->fwnode->dev != dev)
> +		return;
> +
> +	sibling = bus_find_device(dev->bus, NULL, dev, fwnode_shared_bound_match);
> +	if (sibling) {
> +		dev->fwnode->dev = sibling;

[Severity: High]
Can this assignment result in a use-after-free of the sibling device pointer?

This assigns dev->fwnode->dev to the matched sibling locklessly. If the
sibling is concurrently being unregistered, its device_del() routine will run
this check early in the teardown:

if (dev->fwnode && dev->fwnode->dev == dev)
    dev->fwnode->dev = NULL;

If the ownership is transferred to the sibling right after device_del() passes
this check, the fwnode->dev pointer will never be cleared when the sibling is
subsequently freed, leaving a dangling pointer that can be accessed later.

> +		fwnode_links_purge_suppliers(dev->fwnode);
> +		fw_devlink_pickup_dangling_consumers(sibling);
> +		put_device(sibling);
> +	} else {
> +		dev->fwnode->dev = NULL;
> +	}
> +}
> +
>  /**
>   * __device_links_no_driver - Update links of a device without a driver.
>   * @dev: Device without a drvier.
> diff --git a/drivers/base/dd.c b/drivers/base/dd.c
> --- a/drivers/base/dd.c
> +++ b/drivers/base/dd.c
[ ... ]
> @@ -762,6 +762,15 @@ static int really_probe(struct device *dev, const struct device_driver *drv)
>  dev_groups_failed:
>  	device_remove(dev);
>  probe_failed:
> +	/*
> +	 * -ENODEV/-ENXIO mean the driver definitively rejected this device
> +	 * (errors are returned as positive values at this label). If it owns a
> +	 * fwnode shared with sibling devices (e.g. SCMI creates several devices
> +	 * per protocol node), hand the fwnode off so its dangling child
> +	 * consumers can be resolved by a sibling instead of deferring forever.
> +	 */
> +	if (ret == ENODEV || ret == ENXIO)
> +		fw_devlink_release_shared_fwnode(dev);

[Severity: Medium]
Because this handoff is initiated while dev->driver is still set (it gets
cleared much later in device_unbind_cleanup()), does this create the race
window with device_links_driver_bound() described earlier?

A successfully probing sibling running device_links_driver_bound() will see
the populated ->driver pointer and incorrectly assume the current owner is
still active, missing the handoff.

>  	driver_sysfs_remove(dev);
>  sysfs_failed:
>  	bus_notify(dev, BUS_NOTIFY_DRIVER_NOT_BOUND);

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260928-driver-core-v1-1-0846bb8e0f32@nxp.com?part=1

  reply	other threads:[~2026-09-28 12:04 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-28 11:49 [PATCH] driver core: hand off fwnode ownership when shared fwnode owner is rejected Peng Fan (OSS)
2026-09-28 12:04 ` sashiko-bot [this message]
2026-09-28 12:09 ` Sudeep Holla
2026-09-29  1:47   ` Peng Fan
2026-09-29  8:35     ` Sudeep Holla
2026-09-29 15:56       ` Sudeep Holla
2026-09-30  7:06         ` Peng Fan
2026-09-30  8:24           ` Sudeep Holla

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=20260928120414.CB8CD1F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=Frank.Li@kernel.org \
    --cc=imx@lists.linux.dev \
    --cc=peng.fan@oss.nxp.com \
    --cc=sashiko-reviews@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.