perf: hisi: Fix use-after-free when register pmu fails
authorJunhao He <hejunhao3@huawei.com>
Tue, 24 Oct 2023 11:36:30 +0000 (19:36 +0800)
committerWill Deacon <will@kernel.org>
Tue, 24 Oct 2023 12:30:02 +0000 (13:30 +0100)
When we fail to register the uncore pmu, the pmu context may not been
allocated. The error handing will call cpuhp_state_remove_instance()
to call uncore pmu offline callback, which migrate the pmu context.
Since that's liable to lead to some kind of use-after-free.

Use cpuhp_state_remove_instance_nocalls() instead of
cpuhp_state_remove_instance() so that the notifiers don't execute after
the PMU device has been failed to register.

Fixes: a0ab25cd82ee ("drivers/perf: hisi: Add support for HiSilicon PA PMU driver")
FIxes: 3bf30882c3c7 ("drivers/perf: hisi: Add support for HiSilicon SLLC PMU driver")
Signed-off-by: Junhao He <hejunhao3@huawei.com>
Link: https://lore.kernel.org/r/20231024113630.13472-1-hejunhao3@huawei.com
Signed-off-by: Will Deacon <will@kernel.org>
drivers/perf/hisilicon/hisi_uncore_pa_pmu.c
drivers/perf/hisilicon/hisi_uncore_sllc_pmu.c

index d941e746b42483069a59cb0290f33de2d4dc6761..797cf201996a9646490ee52aee421dfa969dbc61 100644 (file)
@@ -505,8 +505,8 @@ static int hisi_pa_pmu_probe(struct platform_device *pdev)
        ret = perf_pmu_register(&pa_pmu->pmu, name, -1);
        if (ret) {
                dev_err(pa_pmu->dev, "PMU register failed, ret = %d\n", ret);
-               cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
-                                           &pa_pmu->node);
+               cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_PA_ONLINE,
+                                                   &pa_pmu->node);
                return ret;
        }
 
index 6fe534a665eda3cd37989e2ff25f24e1a7db1dc5..e706ca5676764b9186a18cd982b29aec907c8231 100644 (file)
@@ -450,8 +450,8 @@ static int hisi_sllc_pmu_probe(struct platform_device *pdev)
        ret = perf_pmu_register(&sllc_pmu->pmu, name, -1);
        if (ret) {
                dev_err(sllc_pmu->dev, "PMU register failed, ret = %d\n", ret);
-               cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
-                                           &sllc_pmu->node);
+               cpuhp_state_remove_instance_nocalls(CPUHP_AP_PERF_ARM_HISI_SLLC_ONLINE,
+                                                   &sllc_pmu->node);
                return ret;
        }