[PATCH 1/2] peci: Fix use-after-free in unregister_controller()
From: Suyuan Wang
Date: Tue Nov 10 2026 - 12:06:35 EST
unregister_controller() keeps using the controller after
device_unregister():
device_unregister(&controller->dev);
fwnode_handle_put(controller->dev.fwnode);
pm_runtime_disable(&controller->dev);
The child devices are already gone at this point, so device_unregister()
normally drops the last reference and peci_controller_dev_release()
frees the controller. The fwnode read and pm_runtime_disable() that
follow then touch freed memory. This runs every time a PECI controller
driver is unbound or its module is removed.
Fix it by saving the fwnode pointer first, disabling runtime PM before
unregistering, and putting the fwnode only after device_unregister().
Found with a static analysis tool and checked by hand.
Fixes: 6523d3b2ffa2 ("peci: Add core infrastructure")
Cc: stable@xxxxxxxxxxxxxxx
Co-developed-by: Kaixuan Li <kaixuan.li@xxxxxxxxxx>
Signed-off-by: Kaixuan Li <kaixuan.li@xxxxxxxxxx>
Signed-off-by: Suyuan Wang <stevewong@xxxxxxxxxxx>
---
Compile tested only, I don't have PECI hardware.
drivers/peci/core.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/peci/core.c b/drivers/peci/core.c
index e14995b1bf7f..247a287f87ca 100644
--- a/drivers/peci/core.c
+++ b/drivers/peci/core.c
@@ -88,6 +88,7 @@ static int unregister_child(struct device *dev, void *dummy)
static void unregister_controller(void *_controller)
{
struct peci_controller *controller = _controller;
+ struct fwnode_handle *fwnode = controller->dev.fwnode;
/*
* Detach any active PECI devices. This can't fail, thus we do not
@@ -95,11 +96,12 @@ static void unregister_controller(void *_controller)
*/
device_for_each_child_reverse(&controller->dev, NULL, unregister_child);
- device_unregister(&controller->dev);
+ pm_runtime_disable(&controller->dev);
- fwnode_handle_put(controller->dev.fwnode);
+ /* May drop the last reference and free the controller. */
+ device_unregister(&controller->dev);
- pm_runtime_disable(&controller->dev);
+ fwnode_handle_put(fwnode);
}
/**
--
2.34.1