cpc_desc_ptr embeds a struct kobject that is registered in sysfs via
kobject_init_and_add(), but cppc_ktype lacked a .release callback and
acpi_cppc_processor_exit() freed cpc_ptr immediately after kobject_put().
With CONFIG_DEBUG_KOBJECT_RELEASE=y, this causes a use-after-free when
kobject_delayed_cleanup() runs on freed memory.

Move the sys_mem_vaddr unmapping and kfree(cpc_ptr) into a new
cppc_release() callback on cppc_ktype, and initialize the kobject on
allocation so kobject_put() handles cleanup in all paths.

Fixes: 158c998ea44b ("ACPI / CPPC: add sysfs support to compute delivered 
performance")
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <[email protected]>
---
 drivers/acpi/cppc_acpi.c | 39 ++++++++++++++++++---------------------
 1 file changed, 18 insertions(+), 21 deletions(-)

diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c
index fef54fcd00b7..2a80404f85d3 100644
--- a/drivers/acpi/cppc_acpi.c
+++ b/drivers/acpi/cppc_acpi.c
@@ -297,7 +297,22 @@ static struct attribute *cppc_attrs[] = {
 };
 ATTRIBUTE_GROUPS(cppc);
 
+static void cppc_release(struct kobject *kobj)
+{
+       struct cpc_desc *cpc_ptr = to_cpc_desc(kobj);
+       unsigned int i;
+
+       for (i = 2; i < cpc_ptr->num_entries; i++) {
+               void __iomem *addr = cpc_ptr->cpc_regs[i - 2].sys_mem_vaddr;
+
+               if (addr)
+                       iounmap(addr);
+       }
+       kfree(cpc_ptr);
+}
+
 static const struct kobj_type cppc_ktype = {
+       .release = cppc_release,
        .sysfs_ops = &kobj_sysfs_ops,
        .default_groups = cppc_groups,
 };
@@ -799,6 +814,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
                ret = -ENOMEM;
                goto out_buf_free;
        }
+       kobject_init(&cpc_ptr->kobj, &cppc_ktype);
 
        /* First entry is NumEntries. */
        cpc_obj = &out_obj->package.elements[0];
@@ -1001,11 +1017,9 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        /* Plug PSD data into this CPU's CPC descriptor. */
        per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr;
 
-       ret = kobject_init_and_add(&cpc_ptr->kobj, &cppc_ktype, &cpu_dev->kobj,
-                       "acpi_cppc");
+       ret = kobject_add(&cpc_ptr->kobj, &cpu_dev->kobj, "acpi_cppc");
        if (ret) {
                per_cpu(cpc_desc_ptr, pr->id) = NULL;
-               kobject_put(&cpc_ptr->kobj);
                goto out_free;
        }
 
@@ -1013,14 +1027,7 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr)
        return 0;
 
 out_free:
-       /* Free all the mapped sys mem areas for this CPU */
-       for (i = 2; i < cpc_ptr->num_entries; i++) {
-               void __iomem *addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr;
-
-               if (addr)
-                       iounmap(addr);
-       }
-       kfree(cpc_ptr);
+       kobject_put(&cpc_ptr->kobj);
 
 out_buf_free:
        kfree(output.pointer);
@@ -1037,8 +1044,6 @@ EXPORT_SYMBOL_GPL(acpi_cppc_processor_probe);
 void acpi_cppc_processor_exit(struct acpi_processor *pr)
 {
        struct cpc_desc *cpc_ptr;
-       unsigned int i;
-       void __iomem *addr;
        int pcc_ss_id = per_cpu(cpu_pcc_subspace_idx, pr->id);
 
        if (pcc_ss_id >= 0 && pcc_data[pcc_ss_id]) {
@@ -1056,15 +1061,7 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr)
        if (!cpc_ptr)
                return;
 
-       /* Free all the mapped sys mem areas for this CPU */
-       for (i = 2; i < cpc_ptr->num_entries; i++) {
-               addr = cpc_ptr->cpc_regs[i-2].sys_mem_vaddr;
-               if (addr)
-                       iounmap(addr);
-       }
-
        kobject_put(&cpc_ptr->kobj);
-       kfree(cpc_ptr);
 }
 EXPORT_SYMBOL_GPL(acpi_cppc_processor_exit);
 
-- 
2.56.0.385.gd3acb90ef8-goog


Reply via email to