* [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release
@ 2026-11-10 8:51 Johan Hovold
2026-11-10 8:51 ` [PATCH v2 1/8] " Johan Hovold
` (7 more replies)
0 siblings, 8 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel
When fixing a use-after-free regression in 7.3, I noticed that the
software node implementation is internally inconsistent.
Specifically, the firmware node pointer of a struct device may point to
either a primary or secondary firmware node, but in several places
kernel-doc and comments suggests that the firmware node pointer always
points to a primary node (cf. [1][2]).
This series fixes the 7.3 regression along with a similar issue in i2c
core due which are both stem from the fact that
device_remove_software_node() happens to drop a reference to a primary
software node that was never added by device_add_software_node().
The next two patches clarify that device_remove_software_node() should
only be used to remove nodes added by device_add_software_node() and
stops touching primary nodes.
The rest of the series addresses further inconsistencies.
The first two fixes could go into 7.4 and the rest (which depends on the
fixes) into 7.5. And with an ack from the i2c maintainer for patches 2/8
and 4/8.
Johan
[1] 97badf873ab6 ("device property: Make it possible to use secondary firmware nodes")
[2] 3f7bddaf5d5a ("device property: add description of fwnode cases")
Changes in v2
- rename temporary variable and amend comment as dev->fwnode is not
always a primary node (patch 1/8)
- fix related UAF in i2c core (patch 2/8, new)
- fix inconsistencies in interfaces, kernel-doc, and comments (patches
3-8, new).
Johan Hovold (8):
driver core: platform: fix swnode use-after-free on device release
i2c: core: fix swnode use-after-free on client deregistration
swnode: fix device_add_of_node() kernel doc
swnode: ignore primary nodes in device_remove_software_node()
driver core: platform: warn on bad fwnode assignment
driver core: platform: tests: fix swnode reuse test description
swnode: fix software_node_notify() primary node comment
device property: fix fwnode_get_next_child_node() comments
drivers/base/core.c | 3 ++-
drivers/base/platform.c | 32 +++++++++++-------------
drivers/base/property.c | 6 ++---
drivers/base/swnode.c | 20 ++++++++-------
drivers/base/test/platform-device-test.c | 5 ++--
drivers/i2c/i2c-core-base.c | 10 +++-----
include/linux/device.h | 1 +
7 files changed, 39 insertions(+), 38 deletions(-)
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 1/8] driver core: platform: fix swnode use-after-free on device release
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
@ 2026-11-10 8:51 ` Johan Hovold
2026-11-10 8:51 ` [PATCH v2 2/8] i2c: core: fix swnode use-after-free on client deregistration Johan Hovold
` (6 subsequent siblings)
7 siblings, 0 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, stable, Bartosz Golaszewski
When a device has a software node, device_remove_software_node() may
drop the last reference and free it during platform_device_release().
If the software node is the also the primary node then the device fwnode
pointer is never cleared.
Use a temporary variable to track whether the firmware node is a
software node to avoid a use-after-free in is_software_node() and having
fwnode_handle_put() call a function pointer via poisoned or reallocated
memory when the primary node is a software node.
This issue was flagged by Sashiko when reviewing a related fix.
Fixes: 7d80509ff0da ("driver core: platform: unify release path")
Closes: https://sashiko.dev/#/bug/linux-b860000b-f1d0-46a0-ab52-d47cec8eab99
Cc: stable@vger.kernel.org # 7.3
Cc: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/base/platform.c | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index 979593e5cca1..be5d2f315fdb 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -598,13 +598,14 @@ static void platform_device_release(struct device *dev)
{
struct platform_object *pa = container_of(dev, struct platform_object,
pdev.dev);
+ bool fwnode_is_software_node = is_software_node(dev_fwnode(dev));
device_remove_software_node(dev);
/*
- * If the primary firmware node is a software node, its reference count
- * was already decreased by the call to device_remove_software_node().
+ * If the firmware node is a software node, its reference count
+ * was decremented by device_remove_software_node().
*/
- if (!is_software_node(dev_fwnode(dev)))
+ if (!fwnode_is_software_node)
fwnode_handle_put(pa->pdev.dev.fwnode);
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.mfd_cell);
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 2/8] i2c: core: fix swnode use-after-free on client deregistration
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
2026-11-10 8:51 ` [PATCH v2 1/8] " Johan Hovold
@ 2026-11-10 8:51 ` Johan Hovold
2026-11-10 10:58 ` Andy Shevchenko
2026-11-10 8:51 ` [PATCH v2 3/8] swnode: fix device_add_of_node() kernel doc Johan Hovold
` (5 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, stable, Hans de Goede
If a client has both a primary and a secondary firmware node, the
secondary node is accessed via the ->secondary pointer of the primary
node.
Use a temporary variable to track whether the firmware node is a
software node and remove any software node before dropping its reference
to avoid a use-after-free in device_remove_software_node() when
accessing the secondary firmware node.
Fixes: df6d7277e552 ("i2c: core: Do not dereference fwnode in struct device")
Fixes: 1c24e5fc0c70 ("i2c: core: Fix double-free of fwnode in i2c_unregister_device()")
Cc: stable@vger.kernel.org # 6.16
Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Cc: Hans de Goede <hansg@kernel.org>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/i2c/i2c-core-base.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 81603317b64d..c55ca14eaad9 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -1056,6 +1056,7 @@ EXPORT_SYMBOL_GPL(i2c_new_client_device);
void i2c_unregister_device(struct i2c_client *client)
{
struct fwnode_handle *fwnode;
+ bool fwnode_is_software_node;
if (IS_ERR_OR_NULL(client))
return;
@@ -1066,14 +1067,14 @@ void i2c_unregister_device(struct i2c_client *client)
else if (is_acpi_device_node(fwnode))
acpi_device_clear_enumerated(to_acpi_device_node(fwnode));
+ fwnode_is_software_node = is_software_node(fwnode);
+ device_remove_software_node(&client->dev);
/*
- * If the primary fwnode is a software node it is free-ed by
- * device_remove_software_node() below, avoid double-free.
+ * If the firmware node is a software node, its reference count
+ * was decremented by device_remove_software_node().
*/
- if (!is_software_node(fwnode))
+ if (!fwnode_is_software_node)
fwnode_handle_put(fwnode);
-
- device_remove_software_node(&client->dev);
device_unregister(&client->dev);
}
EXPORT_SYMBOL_GPL(i2c_unregister_device);
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 3/8] swnode: fix device_add_of_node() kernel doc
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
2026-11-10 8:51 ` [PATCH v2 1/8] " Johan Hovold
2026-11-10 8:51 ` [PATCH v2 2/8] i2c: core: fix swnode use-after-free on client deregistration Johan Hovold
@ 2026-11-10 8:51 ` Johan Hovold
2026-11-10 10:42 ` Johan Hovold
2026-11-10 11:00 ` Andy Shevchenko
2026-11-10 8:51 ` [PATCH v2 4/8] swnode: ignore primary nodes in device_remove_software_node() Johan Hovold
` (4 subsequent siblings)
7 siblings, 2 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel
Software nodes added to a device by device_add_software_node() are
always secondary firmware nodes even if they may be stored in the
dev->fwnode pointer.
Fix the kernel doc which incorrectly claims that a software node added
using this interface "could become the primary node".
Also clarify that device_remove_software_node() should only be used to
remove software nodes added by device_add_software_node().
Fixes: e68d0119e328 ("software node: Introduce device_add_software_node()")
Cc: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/base/swnode.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 65e9388af865..5dc2029f9a7b 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -1055,9 +1055,8 @@ EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
* @dev: The device the software node is meant for.
* @node: The software node.
*
- * This function will make @node the secondary firmware node pointer of @dev. If
- * @dev has no primary node, then @node will become the primary node. The
- * function will register @node automatically if it wasn't already registered.
+ * Register @node if it was not already registered and make it the secondary
+ * firmware node of @dev.
*/
int device_add_software_node(struct device *dev, const struct software_node *node)
{
@@ -1098,7 +1097,8 @@ EXPORT_SYMBOL_GPL(device_add_software_node);
* device_remove_software_node - Remove device's software node
* @dev: The device with the software node.
*
- * This function will unregister the software node of @dev.
+ * Remove a software node added by device_add_software_node() and
+ * deregister it if this is the last reference.
*/
void device_remove_software_node(struct device *dev)
{
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 4/8] swnode: ignore primary nodes in device_remove_software_node()
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
` (2 preceding siblings ...)
2026-11-10 8:51 ` [PATCH v2 3/8] swnode: fix device_add_of_node() kernel doc Johan Hovold
@ 2026-11-10 8:51 ` Johan Hovold
2026-11-10 11:05 ` Andy Shevchenko
2026-11-10 8:51 ` [PATCH v2 5/8] driver core: platform: warn on bad fwnode assignment Johan Hovold
` (3 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel
device_remove_software_node() should only be used to remove secondary
firmware nodes added by device_add_software_node() but will currently
drop a reference also if a device has a primary software node.
Bail out early if device_remove_software_node() is called for a device
whose primary firmware node is a software node and fix up the two
callers that currently work around this themselves.
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/base/core.c | 3 ++-
drivers/base/platform.c | 9 ++++-----
drivers/base/swnode.c | 3 +++
drivers/i2c/i2c-core-base.c | 9 +++------
include/linux/device.h | 1 +
5 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index bf97b06337a1..460c7ad1eaeb 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -5212,10 +5212,11 @@ int dev_warn_probe(const struct device *dev, int err, const char *fmt, ...)
}
EXPORT_SYMBOL_GPL(dev_warn_probe);
-static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
+bool fwnode_is_primary(struct fwnode_handle *fwnode)
{
return fwnode && !IS_ERR(fwnode->secondary);
}
+EXPORT_SYMBOL_GPL(fwnode_is_primary);
/**
* set_primary_fwnode - Change the primary firmware node of a given device.
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index be5d2f315fdb..e0b38dbd5acf 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -598,15 +598,14 @@ static void platform_device_release(struct device *dev)
{
struct platform_object *pa = container_of(dev, struct platform_object,
pdev.dev);
- bool fwnode_is_software_node = is_software_node(dev_fwnode(dev));
device_remove_software_node(dev);
/*
- * If the firmware node is a software node, its reference count
- * was decremented by device_remove_software_node().
+ * Must be done after device_remove_software_node() which may have
+ * freed a secondary firmware node and cleared the fwnode pointer.
*/
- if (!fwnode_is_software_node)
- fwnode_handle_put(pa->pdev.dev.fwnode);
+ fwnode_handle_put(dev->fwnode);
+
kfree(pa->pdev.dev.platform_data);
kfree(pa->pdev.mfd_cell);
kfree(pa->pdev.resource);
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index 5dc2029f9a7b..a90c20cb84e6 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -1108,6 +1108,9 @@ void device_remove_software_node(struct device *dev)
if (!swnode)
return;
+ if (fwnode_is_primary(&swnode->fwnode))
+ return;
+
if (device_is_registered(dev))
software_node_notify_remove(dev);
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index c55ca14eaad9..af3ae2a83626 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -1056,7 +1056,6 @@ EXPORT_SYMBOL_GPL(i2c_new_client_device);
void i2c_unregister_device(struct i2c_client *client)
{
struct fwnode_handle *fwnode;
- bool fwnode_is_software_node;
if (IS_ERR_OR_NULL(client))
return;
@@ -1067,14 +1066,12 @@ void i2c_unregister_device(struct i2c_client *client)
else if (is_acpi_device_node(fwnode))
acpi_device_clear_enumerated(to_acpi_device_node(fwnode));
- fwnode_is_software_node = is_software_node(fwnode);
device_remove_software_node(&client->dev);
/*
- * If the firmware node is a software node, its reference count
- * was decremented by device_remove_software_node().
+ * Must be done after device_remove_software_node() which may have
+ * freed a secondary firmware node and cleared the fwnode pointer.
*/
- if (!fwnode_is_software_node)
- fwnode_handle_put(fwnode);
+ fwnode_handle_put(client->dev.fwnode);
device_unregister(&client->dev);
}
EXPORT_SYMBOL_GPL(i2c_unregister_device);
diff --git a/include/linux/device.h b/include/linux/device.h
index 6b082c638d45..229a15625766 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -1280,6 +1280,7 @@ int lock_device_hotplug_sysfs(void);
int device_offline(struct device *dev);
int device_online(struct device *dev);
+bool fwnode_is_primary(struct fwnode_handle *fwnode);
void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
void device_set_node(struct device *dev, struct fwnode_handle *fwnode);
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 5/8] driver core: platform: warn on bad fwnode assignment
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
` (3 preceding siblings ...)
2026-11-10 8:51 ` [PATCH v2 4/8] swnode: ignore primary nodes in device_remove_software_node() Johan Hovold
@ 2026-11-10 8:51 ` Johan Hovold
2026-11-10 10:47 ` Johan Hovold
2026-11-10 8:51 ` [PATCH v2 6/8] driver core: platform: tests: fix swnode reuse test description Johan Hovold
` (2 subsequent siblings)
7 siblings, 1 reply; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, Bartosz Golaszewski
Commit e6054f410c97 ("driver core: platform: amend the API contract for
fwnode setters") added a warning to platform_device_set_fwnode() in case
the current firmware node pointer points to a software node as that may
prevent software_node_notify_remove() from being called.
This is only an issue if the platform device has been registered however
as software_node_notify() is only called for registered devices. A
bigger issue is that a secondary firmware node assigned before the call
may be silently lost (and leaked in case of software nodes) as these
helpers do not use set_primary_fwnode().
Replace the current software node check with a warning in case the
device already has a primary or secondary firmware node assigned to
catch any (hard-to-debug) issues due to a secondary node being assigned
before the call.
Note that this also avoids making claims about the device firmware node
pointing to the primary firmware node, which is not the case when the
device only has a secondary node.
Fixes: e6054f410c97 ("driver core: platform: amend the API contract for fwnode setters")
Cc: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/base/platform.c | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index e0b38dbd5acf..869c044f8182 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -709,8 +709,7 @@ EXPORT_SYMBOL_GPL(platform_device_add_data);
* Assign an OF node to this platform device. Internally keep track of the
* reference count. Devices created with platform_device_alloc() must use this
* function instead of assigning the node manually. This function must not be
- * called for a platform device that already has a software node as its primary
- * firmware node assigned.
+ * called for a platform device that already has a firmware node assigned.
*/
void platform_device_set_of_node(struct platform_device *pdev,
struct device_node *np)
@@ -727,19 +726,16 @@ EXPORT_SYMBOL_GPL(platform_device_set_of_node);
* Assign a firmware node to this platform device. Internally keep track of the
* reference count. Devices created with platform_device_alloc() must use this
* function instead of assigning the node manually. This function must not be
- * called for a platform device that already has a software node as its primary
- * firmware node assigned.
+ * called for a platform device that already has a firmware node assigned.
*/
void platform_device_set_fwnode(struct platform_device *pdev,
struct fwnode_handle *fwnode)
{
/*
- * If we call this function for a platform device whose primary
- * firmware node is a software node, we'll never end up calling the
- * symmetric software_node_notify_remove(). There are no users for this
- * right now in the tree so just disallow it.
+ * A secondary firmware node may be lost as set_primary_fwnode() is
+ * not used here, warn for now if a node has already been set.
*/
- WARN_ON(is_software_node(dev_fwnode(&pdev->dev)));
+ WARN_ON(dev_fwnode(&pdev->dev));
fwnode_handle_put(pdev->dev.fwnode);
device_set_node(&pdev->dev, fwnode_handle_get(fwnode));
}
@@ -752,14 +748,16 @@ EXPORT_SYMBOL_GPL(platform_device_set_fwnode);
*
* Reuses the OF node of another device in this platform device while
* internally keeping track of reference counting. This function must not be
- * called for a platform device that already has a software node as its primary
- * firmware node assigned.
+ * called for a platform device that already has a firmware node assigned.
*/
void platform_device_set_of_node_from_dev(struct platform_device *pdev,
const struct device *dev2)
{
- /* See platform_device_set_fwnode(). */
- WARN_ON(is_software_node(dev_fwnode(&pdev->dev)));
+ /*
+ * A secondary firmware node may be lost as set_primary_fwnode() is
+ * not used here, warn for now if a node has already been set.
+ */
+ WARN_ON(dev_fwnode(&pdev->dev));
device_set_of_node_from_dev(&pdev->dev, dev2);
pdev->dev.fwnode = of_fwnode_handle(pdev->dev.of_node);
}
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 6/8] driver core: platform: tests: fix swnode reuse test description
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
` (4 preceding siblings ...)
2026-11-10 8:51 ` [PATCH v2 5/8] driver core: platform: warn on bad fwnode assignment Johan Hovold
@ 2026-11-10 8:51 ` Johan Hovold
2026-11-10 8:51 ` [PATCH v2 7/8] swnode: fix software_node_notify() primary node comment Johan Hovold
2026-11-10 8:51 ` [PATCH v2 8/8] device property: fix fwnode_get_next_child_node() comments Johan Hovold
7 siblings, 0 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, Bartosz Golaszewski
The description of the software node reuse test is misleading as a
software node being registered does not prevent it from being reused
(e.g. as software nodes can be shared).
Fix the description by clarifying that the test would fail if the
secondary software node is not removed from the device so that the
reused primary firmware node still points to the software node.
Fixes: 397f0a3958c9 ("driver core: platform: tests: add test cases for correct swnode removal")
Cc: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/base/test/platform-device-test.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/base/test/platform-device-test.c b/drivers/base/test/platform-device-test.c
index 9ce563f76aad..b0cc37d166ff 100644
--- a/drivers/base/test/platform-device-test.c
+++ b/drivers/base/test/platform-device-test.c
@@ -273,9 +273,10 @@ static const struct software_node platform_device_test_swnode = { };
/*
* Check that reusing a software node works correctly. If the call to
* platform_device_register_full() fails after adding the secondary firmware
- * node, the software node must be unregistered in the device's release()
+ * node, the software node must be removed in the device's release()
* callback or the subsequent call to platform_device_register_full() will fail
- * with -EBUSY due to the software node already having been registered.
+ * with -EBUSY due to the primary firmware node still pointing at the
+ * secondary software node.
*/
static void platform_device_swnode_add_twice(struct kunit *test)
{
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 7/8] swnode: fix software_node_notify() primary node comment
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
` (5 preceding siblings ...)
2026-11-10 8:51 ` [PATCH v2 6/8] driver core: platform: tests: fix swnode reuse test description Johan Hovold
@ 2026-11-10 8:51 ` Johan Hovold
2026-11-10 8:51 ` [PATCH v2 8/8] device property: fix fwnode_get_next_child_node() comments Johan Hovold
7 siblings, 0 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, Bartosz Golaszewski
The firmware node pointer in struct device may point to either a primary
or a secondary firmware node and driver core sets the dev pointer of
that node when registering devices.
Fix the comments in software_node_notify() and
software_node_notify_remove() which incorrectly suggest that driver
core only sets the dev pointer of primary firmware nodes.
Fixes: 37e586675993 ("software node: add fw_devlink support")
Cc: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/base/swnode.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index a90c20cb84e6..8e12f518e13f 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -1169,8 +1169,8 @@ void software_node_notify(struct device *dev)
return;
/*
- * When the software node is the device's secondary firmware node,
- * the core only records the owning device on the primary fwnode
+ * When a device has both a primary and a secondary firmware node the
+ * core only records the owning device in the primary node
* (see device_add()). fw_devlink resolves a supplier device through
* fwnode->dev, so without this a consumer referencing the software
* node could never find the supplier device and would defer forever.
@@ -1205,9 +1205,8 @@ void software_node_notify_remove(struct device *dev)
sysfs_remove_link(&dev->kobj, "software_node");
/*
- * Drop the device pointer mirrored onto a secondary software node in
- * software_node_notify(). For a primary software node the core owns
- * fwnode->dev and clears it in device_del().
+ * Clear any device pointer set in a secondary software node in
+ * software_node_notify().
*/
if (!device_match_fwnode(dev, &swnode->fwnode) && swnode->fwnode.dev == dev)
swnode->fwnode.dev = NULL;
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v2 8/8] device property: fix fwnode_get_next_child_node() comments
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
` (6 preceding siblings ...)
2026-11-10 8:51 ` [PATCH v2 7/8] swnode: fix software_node_notify() primary node comment Johan Hovold
@ 2026-11-10 8:51 ` Johan Hovold
7 siblings, 0 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 8:51 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich, Johan Hovold
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, Xu Yang
The parent pointer in fwnode_get_next_child_node() may not point to a
primary firmware node so update the comments to reflect that.
While add it, fix an indefinite article in an earlier comment.
Fixes: 190069255582 ("device property: fix infinite loop in fwnode_for_each_child_node()")
Cc: Xu Yang <xu.yang_2@nxp.com>
Signed-off-by: Johan Hovold <johan@kernel.org>
---
drivers/base/property.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/base/property.c b/drivers/base/property.c
index 51109794d727..32df0c6724ac 100644
--- a/drivers/base/property.c
+++ b/drivers/base/property.c
@@ -810,7 +810,7 @@ fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
/*
* If this function is in a loop and the previous iteration returned
- * an child from fwnode->secondary, then we need to use the secondary
+ * a child from fwnode->secondary, then we need to use the secondary
* as parent rather than @fwnode.
*/
if (child) {
@@ -822,12 +822,12 @@ fwnode_get_next_child_node(const struct fwnode_handle *fwnode,
if (IS_ERR_OR_NULL(parent))
return NULL;
- /* Try to find a child in primary fwnode */
+ /* Try to find a child in parent */
next = fwnode_call_ptr_op(parent, get_next_child_node, child);
if (next)
return next;
- /* When no more children in primary, continue with secondary */
+ /* When no more children in parent, continue with any secondary */
return fwnode_get_next_child_node(parent->secondary, NULL);
}
EXPORT_SYMBOL_GPL(fwnode_get_next_child_node);
--
2.56.0
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/8] swnode: fix device_add_of_node() kernel doc
2026-11-10 8:51 ` [PATCH v2 3/8] swnode: fix device_add_of_node() kernel doc Johan Hovold
@ 2026-11-10 10:42 ` Johan Hovold
2026-11-10 11:00 ` Andy Shevchenko
1 sibling, 0 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 10:42 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel
On Tue, Nov 10, 2026 at 09:51:19AM +0100, Johan Hovold wrote:
> Software nodes added to a device by device_add_software_node() are
> always secondary firmware nodes even if they may be stored in the
> dev->fwnode pointer.
>
> Fix the kernel doc which incorrectly claims that a software node added
> using this interface "could become the primary node".
Subject was supposed to refer to device_add_software_node() (as noted by
Sashiko).
Johan
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 5/8] driver core: platform: warn on bad fwnode assignment
2026-11-10 8:51 ` [PATCH v2 5/8] driver core: platform: warn on bad fwnode assignment Johan Hovold
@ 2026-11-10 10:47 ` Johan Hovold
0 siblings, 0 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 10:47 UTC (permalink / raw)
To: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich
Cc: Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, Bartosz Golaszewski
On Tue, Nov 10, 2026 at 09:51:21AM +0100, Johan Hovold wrote:
> Commit e6054f410c97 ("driver core: platform: amend the API contract for
> fwnode setters") added a warning to platform_device_set_fwnode() in case
> the current firmware node pointer points to a software node as that may
> prevent software_node_notify_remove() from being called.
>
> This is only an issue if the platform device has been registered however
> as software_node_notify() is only called for registered devices. A
> bigger issue is that a secondary firmware node assigned before the call
> may be silently lost (and leaked in case of software nodes) as these
> helpers do not use set_primary_fwnode().
>
> Replace the current software node check with a warning in case the
> device already has a primary or secondary firmware node assigned to
> catch any (hard-to-debug) issues due to a secondary node being assigned
> before the call.
>
> Note that this also avoids making claims about the device firmware node
> pointing to the primary firmware node, which is not the case when the
> device only has a secondary node.
>
> Fixes: e6054f410c97 ("driver core: platform: amend the API contract for fwnode setters")
> Cc: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> Signed-off-by: Johan Hovold <johan@kernel.org>
> ---
> drivers/base/platform.c | 24 +++++++++++-------------
> 1 file changed, 11 insertions(+), 13 deletions(-)
> void platform_device_set_fwnode(struct platform_device *pdev,
> struct fwnode_handle *fwnode)
> {
> /*
> - * If we call this function for a platform device whose primary
> - * firmware node is a software node, we'll never end up calling the
> - * symmetric software_node_notify_remove(). There are no users for this
> - * right now in the tree so just disallow it.
> + * A secondary firmware node may be lost as set_primary_fwnode() is
> + * not used here, warn for now if a node has already been set.
> */
> - WARN_ON(is_software_node(dev_fwnode(&pdev->dev)));
> + WARN_ON(dev_fwnode(&pdev->dev));
Sashiko points out that this may trigger a warning on probe deferral in
an ASoC driver due to a new user of platform_device_set_of_node()
currently in linux-next.
Will revisit.
Johan
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/8] i2c: core: fix swnode use-after-free on client deregistration
2026-11-10 8:51 ` [PATCH v2 2/8] i2c: core: fix swnode use-after-free on client deregistration Johan Hovold
@ 2026-11-10 10:58 ` Andy Shevchenko
2026-11-10 11:15 ` Johan Hovold
0 siblings, 1 reply; 15+ messages in thread
From: Andy Shevchenko @ 2026-11-10 10:58 UTC (permalink / raw)
To: Johan Hovold
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, stable, Hans de Goede
On Tue, Nov 10, 2026 at 09:51:18AM +0100, Johan Hovold wrote:
> If a client has both a primary and a secondary firmware node, the
> secondary node is accessed via the ->secondary pointer of the primary
> node.
>
> Use a temporary variable to track whether the firmware node is a
> software node and remove any software node before dropping its reference
> to avoid a use-after-free in device_remove_software_node() when
> accessing the secondary firmware node.
...
> Fixes: df6d7277e552 ("i2c: core: Do not dereference fwnode in struct device")
> Fixes: 1c24e5fc0c70 ("i2c: core: Fix double-free of fwnode in i2c_unregister_device()")
> Cc: stable@vger.kernel.org # 6.16
> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> Cc: Hans de Goede <hansg@kernel.org>
Can we keep these two Cc out of the commit message?
> Signed-off-by: Johan Hovold <johan@kernel.org>
> ---
...
> struct fwnode_handle *fwnode;
> + bool fwnode_is_software_node;
>
> if (IS_ERR_OR_NULL(client))
> return;
> @@ -1066,14 +1067,14 @@ void i2c_unregister_device(struct i2c_client *client)
> else if (is_acpi_device_node(fwnode))
> acpi_device_clear_enumerated(to_acpi_device_node(fwnode));
>
> + fwnode_is_software_node = is_software_node(fwnode);
> + device_remove_software_node(&client->dev);
> /*
> - * If the primary fwnode is a software node it is free-ed by
> - * device_remove_software_node() below, avoid double-free.
> + * If the firmware node is a software node, its reference count
> + * was decremented by device_remove_software_node().
> */
> - if (!is_software_node(fwnode))
> + if (!fwnode_is_software_node)
> fwnode_handle_put(fwnode);
Do I understand correctly that this is a dup with the platform device case? Can
we make a helper (on swnode API level) to cover any other existing or potential
case to avoid similar issues in the future?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 3/8] swnode: fix device_add_of_node() kernel doc
2026-11-10 8:51 ` [PATCH v2 3/8] swnode: fix device_add_of_node() kernel doc Johan Hovold
2026-11-10 10:42 ` Johan Hovold
@ 2026-11-10 11:00 ` Andy Shevchenko
1 sibling, 0 replies; 15+ messages in thread
From: Andy Shevchenko @ 2026-11-10 11:00 UTC (permalink / raw)
To: Johan Hovold
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel
On Tue, Nov 10, 2026 at 09:51:19AM +0100, Johan Hovold wrote:
> Software nodes added to a device by device_add_software_node() are
> always secondary firmware nodes even if they may be stored in the
> dev->fwnode pointer.
>
> Fix the kernel doc which incorrectly claims that a software node added
> using this interface "could become the primary node".
>
> Also clarify that device_remove_software_node() should only be used to
> remove software nodes added by device_add_software_node().
...
> * @dev: The device the software node is meant for.
> * @node: The software node.
> *
> - * This function will make @node the secondary firmware node pointer of @dev. If
> - * @dev has no primary node, then @node will become the primary node. The
> - * function will register @node automatically if it wasn't already registered.
> + * Register @node if it was not already registered and make it the secondary
> + * firmware node of @dev.
While at it, please add a missing Return section (as kernel-doc complains about).
> */
> int device_add_software_node(struct device *dev, const struct software_node *node)
> {
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 4/8] swnode: ignore primary nodes in device_remove_software_node()
2026-11-10 8:51 ` [PATCH v2 4/8] swnode: ignore primary nodes in device_remove_software_node() Johan Hovold
@ 2026-11-10 11:05 ` Andy Shevchenko
0 siblings, 0 replies; 15+ messages in thread
From: Andy Shevchenko @ 2026-11-10 11:05 UTC (permalink / raw)
To: Johan Hovold
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel
On Tue, Nov 10, 2026 at 09:51:20AM +0100, Johan Hovold wrote:
> device_remove_software_node() should only be used to remove secondary
> firmware nodes added by device_add_software_node() but will currently
> drop a reference also if a device has a primary software node.
>
> Bail out early if device_remove_software_node() is called for a device
> whose primary firmware node is a software node and fix up the two
> callers that currently work around this themselves.
...
> -static inline bool fwnode_is_primary(struct fwnode_handle *fwnode)
> +bool fwnode_is_primary(struct fwnode_handle *fwnode)
> {
> return fwnode && !IS_ERR(fwnode->secondary);
> }
> +EXPORT_SYMBOL_GPL(fwnode_is_primary);
Do we need this export? I was expecting that this API shouldn't be used in any
of the modules.
...
> +bool fwnode_is_primary(struct fwnode_handle *fwnode);
> void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
> void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode);
> void device_set_node(struct device *dev, struct fwnode_handle *fwnode);
Yeah, I was proposing to have include/device/fwnode.h for these APIs and
accompanying data types...
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2 2/8] i2c: core: fix swnode use-after-free on client deregistration
2026-11-10 10:58 ` Andy Shevchenko
@ 2026-11-10 11:15 ` Johan Hovold
0 siblings, 0 replies; 15+ messages in thread
From: Johan Hovold @ 2026-11-10 11:15 UTC (permalink / raw)
To: Andy Shevchenko
Cc: Greg Kroah-Hartman, Rafael J. Wysocki, Danilo Krummrich,
Daniel Scally, Heikki Krogerus, Sakari Ailus,
Bartosz Golaszewski, Andi Shyti, driver-core, linux-acpi,
linux-i2c, linux-kernel, stable, Hans de Goede
On Tue, Nov 10, 2026 at 12:58:15PM +0200, Andy Shevchenko wrote:
> On Tue, Nov 10, 2026 at 09:51:18AM +0100, Johan Hovold wrote:
> > If a client has both a primary and a secondary firmware node, the
> > secondary node is accessed via the ->secondary pointer of the primary
> > node.
> >
> > Use a temporary variable to track whether the firmware node is a
> > software node and remove any software node before dropping its reference
> > to avoid a use-after-free in device_remove_software_node() when
> > accessing the secondary firmware node.
>
> ...
>
> > Fixes: df6d7277e552 ("i2c: core: Do not dereference fwnode in struct device")
> > Fixes: 1c24e5fc0c70 ("i2c: core: Fix double-free of fwnode in i2c_unregister_device()")
> > Cc: stable@vger.kernel.org # 6.16
>
> > Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > Cc: Hans de Goede <hansg@kernel.org>
>
> Can we keep these two Cc out of the commit message?
I prefer to highlight the authors of the commits mentioned in the Fixes
tag this way.
> > Signed-off-by: Johan Hovold <johan@kernel.org>
> > ---
> > @@ -1066,14 +1067,14 @@ void i2c_unregister_device(struct i2c_client *client)
> > else if (is_acpi_device_node(fwnode))
> > acpi_device_clear_enumerated(to_acpi_device_node(fwnode));
> >
> > + fwnode_is_software_node = is_software_node(fwnode);
> > + device_remove_software_node(&client->dev);
> > /*
> > - * If the primary fwnode is a software node it is free-ed by
> > - * device_remove_software_node() below, avoid double-free.
> > + * If the firmware node is a software node, its reference count
> > + * was decremented by device_remove_software_node().
> > */
> > - if (!is_software_node(fwnode))
> > + if (!fwnode_is_software_node)
> > fwnode_handle_put(fwnode);
>
> Do I understand correctly that this is a dup with the platform device case? Can
> we make a helper (on swnode API level) to cover any other existing or potential
> case to avoid similar issues in the future?
The bug is different, but the fix is the same. This all gets cleaned up
in patch 4/8.
Johan
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2026-11-10 11:15 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10 8:51 [PATCH v2 0/8] driver core: platform: fix swnode use-after-free on device release Johan Hovold
2026-11-10 8:51 ` [PATCH v2 1/8] " Johan Hovold
2026-11-10 8:51 ` [PATCH v2 2/8] i2c: core: fix swnode use-after-free on client deregistration Johan Hovold
2026-11-10 10:58 ` Andy Shevchenko
2026-11-10 11:15 ` Johan Hovold
2026-11-10 8:51 ` [PATCH v2 3/8] swnode: fix device_add_of_node() kernel doc Johan Hovold
2026-11-10 10:42 ` Johan Hovold
2026-11-10 11:00 ` Andy Shevchenko
2026-11-10 8:51 ` [PATCH v2 4/8] swnode: ignore primary nodes in device_remove_software_node() Johan Hovold
2026-11-10 11:05 ` Andy Shevchenko
2026-11-10 8:51 ` [PATCH v2 5/8] driver core: platform: warn on bad fwnode assignment Johan Hovold
2026-11-10 10:47 ` Johan Hovold
2026-11-10 8:51 ` [PATCH v2 6/8] driver core: platform: tests: fix swnode reuse test description Johan Hovold
2026-11-10 8:51 ` [PATCH v2 7/8] swnode: fix software_node_notify() primary node comment Johan Hovold
2026-11-10 8:51 ` [PATCH v2 8/8] device property: fix fwnode_get_next_child_node() comments Johan Hovold
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®