diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 5af7ae27b252..59556b1f3474 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1253,6 +1253,13 @@ int perf_event_max_stack_handler(struct ctl_table *table, int write, #define PERF_SECURITY_KERNEL 2 #define PERF_SECURITY_TRACEPOINT 3 +#define TASK_TOMBSTONE ((void *)-1L) + +static bool is_kernel_event(struct perf_event *event) +{ + return READ_ONCE(event->owner) == TASK_TOMBSTONE; +} + static inline bool perf_paranoid_any(void) { return sysctl_perf_event_paranoid > 2; @@ -1271,12 +1278,19 @@ static inline int perf_allow_kernel(struct perf_event_attr *attr) return security_perf_event_open(attr, PERF_SECURITY_KERNEL); } -static inline int perf_allow_cpu(struct perf_event_attr *attr) +static inline int perf_allow_cpu(struct perf_event *event) { - if (sysctl_perf_event_paranoid > 0 && !capable(CAP_SYS_ADMIN)) + if (sysctl_perf_event_paranoid > 0 && !is_kernel_event(event) && + !capable(CAP_SYS_ADMIN)) { return -EACCES; + } - return security_perf_event_open(attr, PERF_SECURITY_CPU); + /* + * Bypass the system call security check if the + * event creation is from the kernel + */ + return is_kernel_event(event) ? 0 : + security_perf_event_open(&event->attr, PERF_SECURITY_CPU); } static inline int perf_allow_tracepoint(struct perf_event_attr *attr) diff --git a/kernel/events/core.c b/kernel/events/core.c index bd80191171e6..6f0827d6f064 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -164,13 +164,6 @@ static void perf_ctx_unlock(struct perf_cpu_context *cpuctx, raw_spin_unlock(&cpuctx->ctx.lock); } -#define TASK_TOMBSTONE ((void *)-1L) - -static bool is_kernel_event(struct perf_event *event) -{ - return READ_ONCE(event->owner) == TASK_TOMBSTONE; -} - /* * On task ctx scheduling... * @@ -4234,7 +4227,7 @@ find_get_context(struct pmu *pmu, struct task_struct *task, if (!task) { /* Must be root to operate on a CPU event: */ - err = perf_allow_cpu(&event->attr); + err = perf_allow_cpu(event); if (err) return ERR_PTR(err);