Tony Jones 40c1d3
From: Kan Liang <kan.liang@linux.intel.com>
Tony Jones 40c1d3
Date: Fri, 12 Mar 2021 05:21:37 -0800
Tony Jones 40c1d3
Subject: perf/x86/intel: Fix a crash caused by zero PEBS status
Tony Jones 40c1d3
Git-commit: d88d05a9e0b6d9356e97129d4ff9942d765f46ea
Tony Jones 40c1d3
Patch-mainline: v5.12-rc4
Tony Jones 40c1d3
References: CVE-2021-28971 bsc#1184196
Tony Jones 40c1d3
Tony Jones 40c1d3
A repeatable crash can be triggered by the perf_fuzzer on some Haswell
Tony Jones 40c1d3
system.
Tony Jones 40c1d3
https://lore.kernel.org/lkml/7170d3b-c17f-1ded-52aa-cc6d9ae999f4@maine.edu/
Tony Jones 40c1d3
Tony Jones 40c1d3
For some old CPUs (HSW and earlier), the PEBS status in a PEBS record
Tony Jones 40c1d3
may be mistakenly set to 0. To minimize the impact of the defect, the
Tony Jones 40c1d3
commit was introduced to try to avoid dropping the PEBS record for some
Tony Jones 40c1d3
cases. It adds a check in the intel_pmu_drain_pebs_nhm(), and updates
Tony Jones 40c1d3
the local pebs_status accordingly. However, it doesn't correct the PEBS
Tony Jones 40c1d3
status in the PEBS record, which may trigger the crash, especially for
Tony Jones 40c1d3
the large PEBS.
Tony Jones 40c1d3
Tony Jones 40c1d3
It's possible that all the PEBS records in a large PEBS have the PEBS
Tony Jones 40c1d3
status 0. If so, the first get_next_pebs_record_by_bit() in the
Tony Jones 40c1d3
__intel_pmu_pebs_event() returns NULL. The at = NULL. Since it's a large
Tony Jones 40c1d3
PEBS, the 'count' parameter must > 1. The second
Tony Jones 40c1d3
get_next_pebs_record_by_bit() will crash.
Tony Jones 40c1d3
Tony Jones 40c1d3
Besides the local pebs_status, correct the PEBS status in the PEBS
Tony Jones 40c1d3
record as well.
Tony Jones 40c1d3
Tony Jones 40c1d3
Fixes: 01330d7288e0 ("perf/x86: Allow zero PEBS status with only single active event")
Tony Jones 40c1d3
Reported-by: Vince Weaver <vincent.weaver@maine.edu>
Tony Jones 40c1d3
Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tony Jones 40c1d3
Signed-off-by: Kan Liang <kan.liang@linux.intel.com>
Tony Jones 40c1d3
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Tony Jones 40c1d3
Cc: stable@vger.kernel.org
Tony Jones 40c1d3
Link: https://lkml.kernel.org/r/1615555298-140216-1-git-send-email-kan.liang@linux.intel.com
Tony Jones 40c1d3
Tony Jones 40c1d3
Signed-off-by: Tony Jones <tonyj@suse.de>
Tony Jones 40c1d3
---
Tony Jones 40c1d3
 arch/x86/events/intel/ds.c | 2 +-
Tony Jones 40c1d3
 1 file changed, 1 insertion(+), 1 deletion(-)
Tony Jones 40c1d3
Tony Jones 40c1d3
diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c
Tony Jones 40c1d3
index 7ebae1826403..d32b302719fe 100644
Tony Jones 40c1d3
--- a/arch/x86/events/intel/ds.c
Tony Jones 40c1d3
+++ b/arch/x86/events/intel/ds.c
Tony Jones 40c1d3
@@ -2010,7 +2010,7 @@ static void intel_pmu_drain_pebs_nhm(struct pt_regs *iregs, struct perf_sample_d
Tony Jones 40c1d3
 		 */
Tony Jones 40c1d3
 		if (!pebs_status && cpuc->pebs_enabled &&
Tony Jones 40c1d3
 			!(cpuc->pebs_enabled & (cpuc->pebs_enabled-1)))
Tony Jones 40c1d3
-			pebs_status = cpuc->pebs_enabled;
Tony Jones 40c1d3
+			pebs_status = p->status = cpuc->pebs_enabled;
Tony Jones 40c1d3
 
Tony Jones 40c1d3
 		bit = find_first_bit((unsigned long *)&pebs_status,
Tony Jones 40c1d3
 					x86_pmu.max_pebs_events);
Tony Jones 40c1d3