From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932108AbbCIMqr (ORCPT ); Mon, 9 Mar 2015 08:46:47 -0400 Received: from service87.mimecast.com ([91.220.42.44]:40238 "EHLO service87.mimecast.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753726AbbCIMqk (ORCPT ); Mon, 9 Mar 2015 08:46:40 -0400 From: "Suzuki K. Poulose" To: will.deacon@arm.com Cc: a.p.zijlstra@chello.nl, linux@arm.linux.org.uk, acme@kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, punit.agrawal@arm.com, pawel.moll@arm.com, "Suzuki K. Poulose" , Mark Rutland Subject: [PATCH 2/3] arm64/pmu: Reject groups spanning multiple HW PMUs Date: Mon, 9 Mar 2015 12:46:31 +0000 Message-Id: <1425905192-10509-3-git-send-email-suzuki.poulose@arm.com> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1425905192-10509-1-git-send-email-suzuki.poulose@arm.com> References: <1425905192-10509-1-git-send-email-suzuki.poulose@arm.com> X-OriginalArrivalTime: 09 Mar 2015 12:46:36.0023 (UTC) FILETIME=[142AE070:01D05A67] X-MC-Unique: 115030912463807701 Content-Type: text/plain; charset=WINDOWS-1252 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from quoted-printable to 8bit by nfs id t29Cks3D008720 From: "Suzuki K. Poulose" Don't allow grouping hardware events from different PMUs (eg. CCI + CPU). Fixes a crash triggered by perf_fuzzer on Linux-4.0-rc2, with CCI PMU turned on. The validate_event(), after certain checks, assumes that the given hardware pmu event belongs to armpmu, which may not be true always, with other hardware PMUs around (CCI, CCN). Bad mode in Synchronous Abort handler detected, code 0x86000006 -- IABT (current EL) CPU: 0 PID: 1371 Comm: perf_fuzzer Not tainted 3.19.0+ #249 Hardware name: V2F-1XV7 Cortex-A53x2 SMM (DT) task: ffffffc07c73a280 ti: ffffffc07b0a0000 task.ti: ffffffc07b0a0000 PC is at 0x0 LR is at validate_event+0x90/0xa8 pc : [<0000000000000000>] lr : [] pstate: 00000145 sp : ffffffc07b0a3ba0 [< (null)>] (null) [] armpmu_event_init+0x174/0x3cc [] perf_try_init_event+0x34/0x70 [] perf_init_event+0xe0/0x10c [] perf_event_alloc+0x288/0x358 [] SyS_perf_event_open+0x464/0x98c Code: bad PC value Also cleans up the code to use the arm_pmu only when we know that we are dealing with an arm pmu event. Cc: Will Deacon Cc: Mark Rutland Signed-off-by: Suzuki K. Poulose --- arch/arm64/kernel/perf_event.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 25a5308..68a7415 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -322,22 +322,31 @@ out: } static int -validate_event(struct pmu_hw_events *hw_events, - struct perf_event *event) +validate_event(struct pmu *pmu, struct pmu_hw_events *hw_events, + struct perf_event *event) { - struct arm_pmu *armpmu = to_arm_pmu(event->pmu); + struct arm_pmu *armpmu; struct hw_perf_event fake_event = event->hw; struct pmu *leader_pmu = event->group_leader->pmu; if (is_software_event(event)) return 1; + /* + * Reject groups spanning multiple HW PMUs (e.g. CPU + CCI). The + * core perf code won't check that the pmu->ctx == leader->ctx + * until after pmu->event_init(event). + */ + if (event->pmu != pmu) + return 0; + if (event->pmu != leader_pmu || event->state < PERF_EVENT_STATE_OFF) return 1; if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec) return 1; + armpmu = to_arm_pmu(event->pmu); return armpmu->get_event_idx(hw_events, &fake_event) >= 0; } @@ -355,15 +364,15 @@ validate_group(struct perf_event *event) memset(fake_used_mask, 0, sizeof(fake_used_mask)); fake_pmu.used_mask = fake_used_mask; - if (!validate_event(&fake_pmu, leader)) + if (!validate_event(event->pmu, &fake_pmu, leader)) return -EINVAL; list_for_each_entry(sibling, &leader->sibling_list, group_entry) { - if (!validate_event(&fake_pmu, sibling)) + if (!validate_event(event->pmu, &fake_pmu, sibling)) return -EINVAL; } - if (!validate_event(&fake_pmu, event)) + if (!validate_event(event->pmu, &fake_pmu, event)) return -EINVAL; return 0; -- 1.7.9.5