From: sashiko-bot@kernel.org
To: "Peng Fan (OSS)" <peng.fan@oss.nxp.com>
Cc: imx@lists.linux.dev, Frank.Li@kernel.org
Subject: Re: [PATCH 1/4] software node: do not resurrect swnode being released
Date: Wed, 04 Nov 2026 15:54:47 +0000 [thread overview]
Message-ID: <sashiko-outbox-197554@kernel.org> (raw)
In-Reply-To: <20261104-swnode-race-v1-v1-1-9406a67e25be@nxp.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] software node: transient ref in software_node_to_swnode() risks UAF
- [Medium] software node: re-registering named or parent node hits -EEXIST
--
commit d02f059d143a3e75e357a6d906b17afb37852f09
Author: Peng Fan <peng.fan@nxp.com>
software node: do not resurrect swnode being released
This commit updates software node lookup in drivers/base/swnode.c to use
kobject_get_unless_zero() so that zero-reference swnodes awaiting release on
swnode_kset->list are skipped rather than resurrected. It introduces
software_node_to_swnode_get() and software_node_register_node() for callers
that acquire a reference, while keeping software_node_to_swnode() as a
wrapper that drops the reference before returning.
> software node: do not resurrect swnode being released
>
> software_node_to_swnode() walks the kset list under list_lock, but the
> last kobject_put() drops the reference count to zero before
> kobject_cleanup() removes the object from the list. A lookup can
> therefore find a zero-ref swnode and call kobject_get() on it, which
> triggers refcount warnings and a use-after-free.
>
> One way to hit this is the dwc3-imx driver on i.MX95: when
> dwc3_core_probe() returns -EPROBE_DEFER, dwc3_imx_probe() removes the
> static software node from the device, and the deferred probe retry
> immediately adds the same node again. The previous swnode is still
> waiting for its release callback, and CONFIG_DEBUG_KOBJECT_RELEASE makes
> the window large and deterministic.
>
> Fix the lookup by acquiring references with kobject_get_unless_zero()
> and skipping objects that are already in their release path. Use a
> reference-returning variant for callers that keep the node (register,
> unregister and device_add_software_node()) and keep a borrowed-pointer
> variant for software_node_fwnode().
>
> To avoid looking the node up again after registration,
> software_node_register() now uses an internal helper that returns the
> newly created swnode reference, and device_add_software_node() consumes
> that reference directly.
>
> Fixes: 80488a6b1d3c ("software node: Add support for static node descriptors")
> Signed-off-by: Peng Fan <peng.fan@nxp.com>
>
> diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
> index 84a77ffa3dc4b..19a4153f3fac1 100644
> --- a/drivers/base/swnode.c
> +++ b/drivers/base/swnode.c
[ ... ]
> @@ -98,6 +124,21 @@ software_node_to_swnode(const struct software_node *node)
> return swnode;
> }
>
> +/*
> + * Borrowed-pointer variant of software_node_to_swnode_get(). The caller must
> + * guarantee the lifetime of @node by other means.
> + */
> +static struct swnode *
> +software_node_to_swnode(const struct software_node *node)
> +{
> + struct swnode *swnode = software_node_to_swnode_get(node);
> +
> + if (swnode)
> + swnode_put(swnode);
> +
> + return swnode;
> +}
[Severity: High]
Can calling swnode_put(swnode) here drop the final reference and free swnode
before returning it?
In software_node_to_swnode(), software_node_to_swnode_get(node) acquires
swnode_kset->list_lock, increments candidate->kobj.kref (for example from 1
to 2) via kobject_get_unless_zero(), and releases list_lock.
If the owner of the swnode drops its final reference (via
device_remove_software_node(), software_node_unregister(), or
fwnode_remove_software_node()) before software_node_to_swnode() runs
swnode_put(swnode), the owner's kobject_put() only decrements kref from 2 to
1 instead of releasing the object:
1. If the owner immediately re-registers or re-adds the software_node during
that window, software_node_to_swnode_get() sees the dying swnode with
kref == 1 and either fails software_node_register() with -EEXIST or
reattaches the dying swnode in device_add_software_node().
2. When software_node_to_swnode() then calls swnode_put(swnode), it drops
kref from 1 to 0, invoking kobject_release() -> kobject_cleanup() ->
software_node_release() -> kfree(swnode), and returns a dangling swnode
pointer to its caller.
This is reachable through software_node_fwnode() when resolving referenced
supplier or remote nodes (whose lifetimes are not pinned by the caller) in
software_node_get_reference_args(), software_node_graph_get_remote_endpoint(),
and software_node_add_links(), as well as through software_node_unregister():
drivers/base/swnode.c:software_node_unregister() {
struct swnode *swnode;
swnode = software_node_to_swnode(node);
if (swnode)
fwnode_remove_software_node(&swnode->fwnode);
}
Also, the commit message mentions using the reference-returning variant for
unregister ("Use a reference-returning variant for callers that keep the node
(register, unregister and device_add_software_node())"), but
software_node_unregister() still calls software_node_to_swnode(node).
[ ... ]
> @@ -977,21 +1006,39 @@ void software_node_unregister_node_group(const struct software_node * const *nod
> }
> EXPORT_SYMBOL_GPL(software_node_unregister_node_group);
>
> +static struct swnode *
> +software_node_register_node(const struct software_node *node)
> +{
> + struct swnode *parent, *swnode;
> + struct fwnode_handle *fwnode;
> +
> + swnode = software_node_to_swnode_get(node);
> + if (swnode) {
> + swnode_put(swnode);
> + return ERR_PTR(-EEXIST);
> + }
> +
> + parent = software_node_to_swnode_get(node->parent);
> + if (node->parent && !parent)
> + return ERR_PTR(-EINVAL);
> +
> + fwnode = swnode_register(node, parent, 0);
[Severity: Medium]
What happens if a named static software_node (node->name != NULL) or a
parent/child software_node group is removed on -EPROBE_DEFER and
re-registered before kobject_cleanup() runs?
When the last reference to an swnode is dropped via swnode_put() ->
kobject_put(), __kobject_del() (which removes the sysfs directory) and
kobject_put(parent) only run inside kobject_cleanup(), which is delayed by
1-4 seconds on a workqueue when CONFIG_DEBUG_KOBJECT_RELEASE=y.
For unnamed nodes (node->name == NULL, such as dwc3_imx_swnode),
swnode_register() allocates a fresh IDA ID and creates "node1" while "node0"
is still waiting to be cleaned up. However, when node->name is set:
drivers/base/swnode.c:swnode_register() {
...
if (node->name)
ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
parent ? &parent->kobj : NULL,
"%s", node->name);
}
kobject_init_and_add() attempts to create a sysfs directory with the same
name as the dying swnode that is still present in sysfs, failing in
sysfs_create_dir_ns() with -EEXIST and a sysfs_warn_dup() warning.
Similarly, when a node group is unregistered via
software_node_unregister_node_group(), the dying child kobject holds its
reference on parent->kobj until kobject_cleanup() finishes; the parent's
refcount therefore stays non-zero during the delayed release window, and
re-registering the parent in software_node_register_node() still fails with
-EEXIST.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261104-swnode-race-v1-v1-0-9406a67e25be@nxp.com?part=1
next prev parent reply other threads:[~2026-11-04 15:54 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-04 15:43 [PATCH 0/4] software node: fix lookup of swnode in release path Peng Fan (OSS)
2026-11-04 15:43 ` [PATCH 1/4] software node: do not resurrect swnode being released Peng Fan (OSS)
2026-11-04 15:54 ` sashiko-bot [this message]
2026-11-04 15:43 ` [PATCH 2/4] software node: use kobject_get_unless_zero() in software_node_find_by_name() Peng Fan (OSS)
2026-11-04 16:07 ` sashiko-bot
2026-11-04 21:29 ` Andy Shevchenko
2026-11-04 15:43 ` [PATCH 3/4] software node: handle missing remote endpoint node Peng Fan (OSS)
2026-11-04 16:14 ` sashiko-bot
2026-11-04 15:43 ` [PATCH 4/4] software node: skip dying children during traversal Peng Fan (OSS)
2026-11-04 16:22 ` sashiko-bot
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=sashiko-outbox-197554@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