[PATCH] drivers/perf: arm_spe: Use perf_allow_kernel() for permissions

James Clark james.clark at linaro.org
Wed Aug 7 10:54:41 UTC 2024


For other PMUs, PERF_SAMPLE_PHYS_ADDR requires perf_allow_kernel()
rather than just perfmon_capable(). Because PMSCR_EL1_PA is another form
of physical address, make it consistent and use perf_allow_kernel() for
SPE as well. PMSCR_EL1_PCT and PMSCR_EL1_CX also get the same change.

This improves consistency and indirectly fixes the following error
message which is misleading because perf_event_paranoid is not taken
into account by perfmon_capable():

  $ perf record -e arm_spe/pa_enable/

  Error:
  Access to performance monitoring and observability operations is
  limited. Consider adjusting /proc/sys/kernel/perf_event_paranoid
  setting ...

Suggested-by: Al Grant <al.grant at arm.com>
Signed-off-by: James Clark <james.clark at linaro.org>
---
 drivers/perf/arm_spe_pmu.c | 9 ++++-----
 kernel/events/core.c       | 1 +
 security/security.c        | 1 +
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/perf/arm_spe_pmu.c b/drivers/perf/arm_spe_pmu.c
index 9100d82bfabc..3569050f9cf3 100644
--- a/drivers/perf/arm_spe_pmu.c
+++ b/drivers/perf/arm_spe_pmu.c
@@ -41,7 +41,7 @@
 
 /*
  * Cache if the event is allowed to trace Context information.
- * This allows us to perform the check, i.e, perfmon_capable(),
+ * This allows us to perform the check, i.e, perf_allow_kernel(),
  * in the context of the event owner, once, during the event_init().
  */
 #define SPE_PMU_HW_FLAGS_CX			0x00001
@@ -50,7 +50,7 @@ static_assert((PERF_EVENT_FLAG_ARCH & SPE_PMU_HW_FLAGS_CX) == SPE_PMU_HW_FLAGS_C
 
 static void set_spe_event_has_cx(struct perf_event *event)
 {
-	if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && perfmon_capable())
+	if (IS_ENABLED(CONFIG_PID_IN_CONTEXTIDR) && !perf_allow_kernel(&event->attr))
 		event->hw.flags |= SPE_PMU_HW_FLAGS_CX;
 }
 
@@ -745,9 +745,8 @@ static int arm_spe_pmu_event_init(struct perf_event *event)
 
 	set_spe_event_has_cx(event);
 	reg = arm_spe_event_to_pmscr(event);
-	if (!perfmon_capable() &&
-	    (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT)))
-		return -EACCES;
+	if (reg & (PMSCR_EL1_PA | PMSCR_EL1_PCT))
+		return perf_allow_kernel(&event->attr);
 
 	return 0;
 }
diff --git a/kernel/events/core.c b/kernel/events/core.c
index aa3450bdc227..4a69583e329a 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -417,6 +417,7 @@ static struct kmem_cache *perf_event_cache;
  *   2 - disallow kernel profiling for unpriv
  */
 int sysctl_perf_event_paranoid __read_mostly = 2;
+EXPORT_SYMBOL_GPL(sysctl_perf_event_paranoid);
 
 /* Minimum for 512 kiB + 1 user control page */
 int sysctl_perf_event_mlock __read_mostly = 512 + (PAGE_SIZE / 1024); /* 'free' kiB per user */
diff --git a/security/security.c b/security/security.c
index 8cee5b6c6e6d..70cc9206e902 100644
--- a/security/security.c
+++ b/security/security.c
@@ -5610,6 +5610,7 @@ int security_perf_event_open(struct perf_event_attr *attr, int type)
 {
 	return call_int_hook(perf_event_open, attr, type);
 }
+EXPORT_SYMBOL_GPL(security_perf_event_open);
 
 /**
  * security_perf_event_alloc() - Allocate a perf event LSM blob
-- 
2.34.1




More information about the Linux-security-module-archive mailing list