From 377c09d738d74ee059c100e4834fdc5c6736636d Mon Sep 17 00:00:00 2001 From: Patrick Fay Date: Thu, 3 Nov 2016 17:07:16 -0700 Subject: [PATCH] perf: Fix NULL pointer ref in exclude_idle update Commit 573979dee2a7 ("perf: Add support for exclude_idle attribute") registers an idle callback routine armv8pmu_idle_update. Currently the idle update routine might be called before the pmu has allocated all the per_cpu structures. This can result in a null pointer reference. Change arm_pmu_device_probe to allocate the structures via cpu_pmu_init() before the init_fn() call (which eventually does the idle_notify_register call). Change a branch to out_free to out_destroy as out_free doesn't cleanup what was allocated in cpu_pmu_init(). Also have armv8pmu_idle_update check that the structure is not null before using it. Change-Id: Ie1198fc1783804c61467889c68656d6e8c9c9edf Signed-off-by: Patrick Fay --- arch/arm64/kernel/perf_event.c | 3 +++ drivers/perf/arm_pmu.c | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 10db9cbaf49e..e8f5a17707d4 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -590,6 +590,9 @@ static void armv8pmu_idle_update(struct arm_pmu *cpu_pmu) hw_events = this_cpu_ptr(cpu_pmu->hw_events); + if (!hw_events) + return; + for (idx = 0; idx < cpu_pmu->num_events; ++idx) { if (!test_bit(idx, hw_events->used_mask)) diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 71154ec99d3c..13b79438af1c 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -1051,6 +1051,10 @@ int arm_pmu_device_probe(struct platform_device *pdev, pmu->plat_device = pdev; + ret = cpu_pmu_init(pmu); + if (ret) + goto out_free; + if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { init_fn = of_id->data; @@ -1073,13 +1077,9 @@ int arm_pmu_device_probe(struct platform_device *pdev, if (ret) { pr_info("%s: failed to probe PMU!\n", of_node_full_name(node)); - goto out_free; + goto out_destroy; } - ret = cpu_pmu_init(pmu); - if (ret) - goto out_free; - ret = perf_pmu_register(&pmu->pmu, pmu->name, -1); if (ret) goto out_destroy;