[PATCH v2] EDAC/sysfs: Fix UAF in edac_device_register_sysfs_main_kobj()

From: Guangshuo Li

Date: Tue Apr 28 2026 - 12:39:32 EST


If kobject_init_and_add() fails, the error path drops the kobject
reference with kobject_put(). This may call
edac_device_ctrl_master_release(), which drops the module reference and
frees the edac_device_ctl_info object.

However, the same error path then calls module_put(edac_dev->owner),
which dereferences edac_dev after it may have been freed. This can cause
a use-after-free and also drops the module reference twice.

Track whether kobject_init_and_add() has been called. If it has, rely on
the kobject release callback to drop the module reference. Otherwise,
drop the module reference directly.

This issue was found by a static analysis tool I am developing.

Fixes: 17ed808ad2431 ("EDAC: Fix reference count leaks")
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
v2:
- Move kobj_initialized assignment to the kobject_init_and_add() call
site so it records whether the kobject has actually been initialized.

drivers/edac/edac_device_sysfs.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c
index fcebc4ffea26..042a30ed55c6 100644
--- a/drivers/edac/edac_device_sysfs.c
+++ b/drivers/edac/edac_device_sysfs.c
@@ -231,6 +231,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
struct device *dev_root;
const struct bus_type *edac_subsys;
int err = -ENODEV;
+ bool kobj_initialized = false;

edac_dbg(1, "\n");

@@ -256,6 +257,7 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)
if (dev_root) {
err = kobject_init_and_add(&edac_dev->kobj, &ktype_device_ctrl,
&dev_root->kobj, "%s", edac_dev->name);
+ kobj_initialized = true;
put_device(dev_root);
}
if (err) {
@@ -275,8 +277,10 @@ int edac_device_register_sysfs_main_kobj(struct edac_device_ctl_info *edac_dev)

/* Error exit stack */
err_kobj_reg:
- kobject_put(&edac_dev->kobj);
- module_put(edac_dev->owner);
+ if (kobj_initialized)
+ kobject_put(&edac_dev->kobj);
+ else
+ module_put(edac_dev->owner);

err_out:
return err;
--
2.43.0