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
next prev parent 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox