diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index 680458064bb5..4004dbdab9c7 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -95,7 +95,7 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) { return 0; } -static inline void perf_get_data_addr(struct perf_event *event, struct pt_regs *regs, u64 *addrp) { } +static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { } static inline u32 perf_get_misc_flags(struct pt_regs *regs) { return 0; @@ -126,7 +126,7 @@ static unsigned long ebb_switch_in(bool ebb, struct cpu_hw_events *cpuhw) static inline void power_pmu_bhrb_enable(struct perf_event *event) {} static inline void power_pmu_bhrb_disable(struct perf_event *event) {} static void power_pmu_sched_task(struct perf_event_context *ctx, bool sched_in) {} -static inline void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *cpuhw) {} +static inline void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) {} static void pmao_restore_workaround(bool ebb) { } #endif /* CONFIG_PPC32 */ @@ -170,7 +170,7 @@ static inline unsigned long perf_ip_adjust(struct pt_regs *regs) * pointed to by SIAR; this is indicated by the [POWER6_]MMCRA_SDSYNC, the * [POWER7P_]MMCRA_SDAR_VALID bit in MMCRA, or the SDAR_VALID bit in SIER. */ -static inline void perf_get_data_addr(struct perf_event *event, struct pt_regs *regs, u64 *addrp) +static inline void perf_get_data_addr(struct pt_regs *regs, u64 *addrp) { unsigned long mmcra = regs->dsisr; bool sdar_valid; @@ -195,7 +195,8 @@ static inline void perf_get_data_addr(struct perf_event *event, struct pt_regs * if (!(mmcra & MMCRA_SAMPLE_ENABLE) || sdar_valid) *addrp = mfspr(SPRN_SDAR); - if (is_kernel_addr(mfspr(SPRN_SDAR)) && perf_allow_kernel(&event->attr) != 0) + if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN) && + is_kernel_addr(mfspr(SPRN_SDAR))) *addrp = 0; } @@ -434,7 +435,7 @@ static __u64 power_pmu_bhrb_to(u64 addr) } /* Processing BHRB entries */ -static void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events *cpuhw) +static void power_pmu_bhrb_read(struct cpu_hw_events *cpuhw) { u64 val; u64 addr; @@ -462,7 +463,8 @@ static void power_pmu_bhrb_read(struct perf_event *event, struct cpu_hw_events * * exporting it to userspace (avoid exposure of regions * where we could have speculative execution) */ - if (is_kernel_addr(addr) && perf_allow_kernel(&event->attr) != 0) + if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN) && + is_kernel_addr(addr)) continue; /* Branches are read most recent first (ie. mfbhrb 0 is @@ -2066,12 +2068,12 @@ static void record_and_restart(struct perf_event *event, unsigned long val, if (event->attr.sample_type & (PERF_SAMPLE_ADDR | PERF_SAMPLE_PHYS_ADDR)) - perf_get_data_addr(event, regs, &data.addr); + perf_get_data_addr(regs, &data.addr); if (event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK) { struct cpu_hw_events *cpuhw; cpuhw = this_cpu_ptr(&cpu_hw_events); - power_pmu_bhrb_read(event, cpuhw); + power_pmu_bhrb_read(cpuhw); data.br_stack = &cpuhw->bhrb_stack; } diff --git a/arch/x86/events/intel/bts.c b/arch/x86/events/intel/bts.c index 68162163a05d..7139f6bf27ad 100644 --- a/arch/x86/events/intel/bts.c +++ b/arch/x86/events/intel/bts.c @@ -557,11 +557,9 @@ static int bts_event_init(struct perf_event *event) * Note that the default paranoia setting permits unprivileged * users to profile the kernel. */ - if (event->attr.exclude_kernel) { - ret = perf_allow_kernel(&event->attr); - if (ret) - return ret; - } + if (event->attr.exclude_kernel && perf_paranoid_kernel() && + !capable(CAP_SYS_ADMIN)) + return -EACCES; if (x86_add_exclusive(x86_lbr_exclusive_bts)) return -EBUSY; diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 0fc020856e5c..2dd8b0d64295 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3109,9 +3109,8 @@ static int intel_pmu_hw_config(struct perf_event *event) if (x86_pmu.version < 3) return -EINVAL; - ret = perf_allow_cpu(&event->attr); - if (ret) - return ret; + if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) + return -EACCES; event->hw.config |= ARCH_PERFMON_EVENTSEL_ANY; diff --git a/arch/x86/events/intel/p4.c b/arch/x86/events/intel/p4.c index 4f9ac72968db..d32c0eed38ca 100644 --- a/arch/x86/events/intel/p4.c +++ b/arch/x86/events/intel/p4.c @@ -776,9 +776,8 @@ static int p4_validate_raw_event(struct perf_event *event) * the user needs special permissions to be able to use it */ if (p4_ht_active() && p4_event_bind_map[v].shared) { - v = perf_allow_cpu(&event->attr); - if (v) - return v; + if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) + return -EACCES; } /* ESCR EventMask bits may be invalid */ diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 0605f866044a..97a020c616ad 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1777,14 +1777,6 @@ union security_list_options { int (*bpf_prog_alloc_security)(struct bpf_prog_aux *aux); void (*bpf_prog_free_security)(struct bpf_prog_aux *aux); #endif /* CONFIG_BPF_SYSCALL */ -#ifdef CONFIG_PERF_EVENTS - int (*perf_event_open)(struct perf_event_attr *attr, int type); - int (*perf_event_alloc)(struct perf_event *event); - void (*perf_event_free)(struct perf_event *event); - int (*perf_event_read)(struct perf_event *event); - int (*perf_event_write)(struct perf_event *event); - -#endif }; struct security_hook_heads { @@ -2019,13 +2011,6 @@ struct security_hook_heads { struct hlist_head bpf_prog_alloc_security; struct hlist_head bpf_prog_free_security; #endif /* CONFIG_BPF_SYSCALL */ -#ifdef CONFIG_PERF_EVENTS - struct hlist_head perf_event_open; - struct hlist_head perf_event_alloc; - struct hlist_head perf_event_free; - struct hlist_head perf_event_read; - struct hlist_head perf_event_write; -#endif } __randomize_layout; /* diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index f40925aaf35e..205c79491de3 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -55,7 +55,6 @@ struct perf_guest_info_callbacks { #include #include #include -#include #include struct perf_callchain_entry { @@ -705,9 +704,6 @@ struct perf_event { struct perf_cgroup *cgrp; /* cgroup event is attach to */ #endif -#ifdef CONFIG_SECURITY - void *security; -#endif struct list_head sb_list; #endif /* CONFIG_PERF_EVENTS */ }; @@ -1198,46 +1194,24 @@ extern int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, int perf_event_max_stack_handler(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos); -/* Access to perf_event_open(2) syscall. */ -#define PERF_SECURITY_OPEN 0 - -/* Finer grained perf_event_open(2) access control. */ -#define PERF_SECURITY_CPU 1 -#define PERF_SECURITY_KERNEL 2 -#define PERF_SECURITY_TRACEPOINT 3 - static inline bool perf_paranoid_any(void) { return sysctl_perf_event_paranoid > 2; } -static inline int perf_is_paranoid(void) +static inline bool perf_paranoid_tracepoint_raw(void) { return sysctl_perf_event_paranoid > -1; } -static inline int perf_allow_kernel(struct perf_event_attr *attr) +static inline bool perf_paranoid_cpu(void) { - if (sysctl_perf_event_paranoid > 1 && !capable(CAP_SYS_ADMIN)) - return -EACCES; - - return security_perf_event_open(attr, PERF_SECURITY_KERNEL); + return sysctl_perf_event_paranoid > 0; } -static inline int perf_allow_cpu(struct perf_event_attr *attr) +static inline bool perf_paranoid_kernel(void) { - if (sysctl_perf_event_paranoid > 0 && !capable(CAP_SYS_ADMIN)) - return -EACCES; - - return security_perf_event_open(attr, PERF_SECURITY_CPU); -} - -static inline int perf_allow_tracepoint(struct perf_event_attr *attr) -{ - if (sysctl_perf_event_paranoid > -1 && !capable(CAP_SYS_ADMIN)) - return -EPERM; - - return security_perf_event_open(attr, PERF_SECURITY_TRACEPOINT); + return sysctl_perf_event_paranoid > 1; } extern void perf_event_init(void); diff --git a/include/linux/security.h b/include/linux/security.h index f87da8aa7acc..75f4156c84d7 100644 --- a/include/linux/security.h +++ b/include/linux/security.h @@ -1843,41 +1843,5 @@ static inline void free_secdata(void *secdata) { } #endif /* CONFIG_SECURITY */ -#ifdef CONFIG_PERF_EVENTS -struct perf_event_attr; - -#ifdef CONFIG_SECURITY -extern int security_perf_event_open(struct perf_event_attr *attr, int type); -extern int security_perf_event_alloc(struct perf_event *event); -extern void security_perf_event_free(struct perf_event *event); -extern int security_perf_event_read(struct perf_event *event); -extern int security_perf_event_write(struct perf_event *event); -#else -static inline int security_perf_event_open(struct perf_event_attr *attr, - int type) -{ - return 0; -} - -static inline int security_perf_event_alloc(struct perf_event *event) -{ - return 0; -} - -static inline void security_perf_event_free(struct perf_event *event) -{ -} - -static inline int security_perf_event_read(struct perf_event *event) -{ - return 0; -} - -static inline int security_perf_event_write(struct perf_event *event) -{ - return 0; -} -#endif /* CONFIG_SECURITY */ -#endif /* CONFIG_PERF_EVENTS */ - #endif /* ! __LINUX_SECURITY_H */ + diff --git a/kernel/events/core.c b/kernel/events/core.c index fa5048fb7e62..69e6c77e9daf 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -4126,9 +4126,8 @@ 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); - if (err) - return ERR_PTR(err); + if (perf_paranoid_cpu() && !capable(CAP_SYS_ADMIN)) + return ERR_PTR(-EACCES); cpuctx = per_cpu_ptr(pmu->pmu_cpu_context, cpu); ctx = &cpuctx->ctx; @@ -4432,8 +4431,6 @@ static void _free_event(struct perf_event *event) unaccount_event(event); - security_perf_event_free(event); - if (event->rb) { /* * Can happen when we close an event with re-directed output. @@ -4887,10 +4884,6 @@ perf_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) struct perf_event_context *ctx; int ret; - ret = security_perf_event_read(event); - if (ret) - return ret; - ctx = perf_event_ctx_lock(event); ret = __perf_read(event, buf, count); perf_event_ctx_unlock(event, ctx); @@ -5152,11 +5145,6 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg) struct perf_event_context *ctx; long ret; - /* Treat ioctl like writes as it is likely a mutating operation. */ - ret = security_perf_event_write(event); - if (ret) - return ret; - ctx = perf_event_ctx_lock(event); ret = _perf_ioctl(event, cmd, arg); perf_event_ctx_unlock(event, ctx); @@ -5619,10 +5607,6 @@ static int perf_mmap(struct file *file, struct vm_area_struct *vma) if (!(vma->vm_flags & VM_SHARED)) return -EINVAL; - ret = security_perf_event_read(event); - if (ret) - return ret; - vma_size = vma->vm_end - vma->vm_start; if (vma->vm_pgoff == 0) { @@ -5736,7 +5720,7 @@ accounting: lock_limit >>= PAGE_SHIFT; locked = vma->vm_mm->pinned_vm + extra; - if ((locked > lock_limit) && perf_is_paranoid() && + if ((locked > lock_limit) && perf_paranoid_tracepoint_raw() && !capable(CAP_IPC_LOCK)) { ret = -EPERM; goto unlock; @@ -10202,20 +10186,11 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu, } } - err = security_perf_event_alloc(event); - if (err) - goto err_callchain_buffer; - /* symmetric to unaccount_event() in _free_event() */ account_event(event); return event; -err_callchain_buffer: - if (!event->parent) { - if (event->attr.sample_type & PERF_SAMPLE_CALLCHAIN) - put_callchain_buffers(); - } err_addr_filters: kfree(event->addr_filter_ranges); @@ -10333,11 +10308,9 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, attr->branch_sample_type = mask; } /* privileged levels capture (kernel, hv): check permissions */ - if (mask & PERF_SAMPLE_BRANCH_PERM_PLM) { - ret = perf_allow_kernel(attr); - if (ret) - return ret; - } + if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM) + && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) + return -EACCES; } if (attr->sample_type & PERF_SAMPLE_REGS_USER) { @@ -10553,19 +10526,13 @@ SYSCALL_DEFINE5(perf_event_open, if (perf_paranoid_any() && !capable(CAP_SYS_ADMIN)) return -EACCES; - /* Do we allow access to perf_event_open(2) ? */ - err = security_perf_event_open(&attr, PERF_SECURITY_OPEN); - if (err) - return err; - err = perf_copy_attr(attr_uptr, &attr); if (err) return err; if (!attr.exclude_kernel) { - err = perf_allow_kernel(&attr); - if (err) - return err; + if (perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) + return -EACCES; } if (attr.namespaces) { @@ -10582,11 +10549,9 @@ SYSCALL_DEFINE5(perf_event_open, } /* Only privileged users can get physical addresses */ - if ((attr.sample_type & PERF_SAMPLE_PHYS_ADDR)) { - err = perf_allow_kernel(&attr); - if (err) - return err; - } + if ((attr.sample_type & PERF_SAMPLE_PHYS_ADDR) && + perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) + return -EACCES; /* * In cgroup mode, the pid argument is used to pass the fd diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index fb54fdcd11dc..f5b3bf0e69f6 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c @@ -8,7 +8,6 @@ #include #include -#include #include "trace.h" #include "trace_probe.h" @@ -27,10 +26,8 @@ static int total_ref_count; static int perf_trace_event_perm(struct trace_event_call *tp_event, struct perf_event *p_event) { - int ret; - if (tp_event->perf_perm) { - ret = tp_event->perf_perm(tp_event, p_event); + int ret = tp_event->perf_perm(tp_event, p_event); if (ret) return ret; } @@ -49,9 +46,8 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event, /* The ftrace function trace is allowed only for root. */ if (ftrace_event_is_function(tp_event)) { - ret = perf_allow_tracepoint(&p_event->attr); - if (ret) - return ret; + if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) + return -EPERM; if (!is_sampling_event(p_event)) return 0; @@ -86,9 +82,8 @@ static int perf_trace_event_perm(struct trace_event_call *tp_event, * ...otherwise raw tracepoint data can be a severe data leak, * only allow root to have these. */ - ret = perf_allow_tracepoint(&p_event->attr); - if (ret) - return ret; + if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN)) + return -EPERM; return 0; } diff --git a/security/security.c b/security/security.c index 1baf58502368..74dcf97783bb 100644 --- a/security/security.c +++ b/security/security.c @@ -1805,30 +1805,3 @@ void security_bpf_prog_free(struct bpf_prog_aux *aux) call_void_hook(bpf_prog_free_security, aux); } #endif /* CONFIG_BPF_SYSCALL */ - -#ifdef CONFIG_PERF_EVENTS -int security_perf_event_open(struct perf_event_attr *attr, int type) -{ - return call_int_hook(perf_event_open, 0, attr, type); -} - -int security_perf_event_alloc(struct perf_event *event) -{ - return call_int_hook(perf_event_alloc, 0, event); -} - -void security_perf_event_free(struct perf_event *event) -{ - call_void_hook(perf_event_free, event); -} - -int security_perf_event_read(struct perf_event *event) -{ - return call_int_hook(perf_event_read, 0, event); -} - -int security_perf_event_write(struct perf_event *event) -{ - return call_int_hook(perf_event_write, 0, event); -} -#endif /* CONFIG_PERF_EVENTS */ diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 7624ce702aff..109ab510bdb1 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -6940,68 +6940,6 @@ static void selinux_bpf_prog_free(struct bpf_prog_aux *aux) } #endif - -#ifdef CONFIG_PERF_EVENTS -static int selinux_perf_event_open(struct perf_event_attr *attr, int type) -{ - u32 requested, sid = current_sid(); - - if (type == PERF_SECURITY_OPEN) - requested = PERF_EVENT__OPEN; - else if (type == PERF_SECURITY_CPU) - requested = PERF_EVENT__CPU; - else if (type == PERF_SECURITY_KERNEL) - requested = PERF_EVENT__KERNEL; - else if (type == PERF_SECURITY_TRACEPOINT) - requested = PERF_EVENT__TRACEPOINT; - else - return -EINVAL; - - return avc_has_perm(&selinux_state, sid, sid, SECCLASS_PERF_EVENT, - requested, NULL); -} - -static int selinux_perf_event_alloc(struct perf_event *event) -{ - struct perf_event_security_struct *perfsec; - - perfsec = kzalloc(sizeof(*perfsec), GFP_KERNEL); - if (!perfsec) - return -ENOMEM; - - perfsec->sid = current_sid(); - event->security = perfsec; - - return 0; -} - -static void selinux_perf_event_free(struct perf_event *event) -{ - struct perf_event_security_struct *perfsec = event->security; - - event->security = NULL; - kfree(perfsec); -} - -static int selinux_perf_event_read(struct perf_event *event) -{ - struct perf_event_security_struct *perfsec = event->security; - u32 sid = current_sid(); - - return avc_has_perm(&selinux_state, sid, perfsec->sid, - SECCLASS_PERF_EVENT, PERF_EVENT__READ, NULL); -} - -static int selinux_perf_event_write(struct perf_event *event) -{ - struct perf_event_security_struct *perfsec = event->security; - u32 sid = current_sid(); - - return avc_has_perm(&selinux_state, sid, perfsec->sid, - SECCLASS_PERF_EVENT, PERF_EVENT__WRITE, NULL); -} -#endif - static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(binder_set_context_mgr, selinux_binder_set_context_mgr), LSM_HOOK_INIT(binder_transaction, selinux_binder_transaction), @@ -7237,14 +7175,6 @@ static struct security_hook_list selinux_hooks[] __lsm_ro_after_init = { LSM_HOOK_INIT(bpf_map_free_security, selinux_bpf_map_free), LSM_HOOK_INIT(bpf_prog_free_security, selinux_bpf_prog_free), #endif - -#ifdef CONFIG_PERF_EVENTS - LSM_HOOK_INIT(perf_event_open, selinux_perf_event_open), - LSM_HOOK_INIT(perf_event_alloc, selinux_perf_event_alloc), - LSM_HOOK_INIT(perf_event_free, selinux_perf_event_free), - LSM_HOOK_INIT(perf_event_read, selinux_perf_event_read), - LSM_HOOK_INIT(perf_event_write, selinux_perf_event_write), -#endif }; static __init int selinux_init(void) diff --git a/security/selinux/include/classmap.h b/security/selinux/include/classmap.h index f97e7c1db14c..201f7e588a29 100644 --- a/security/selinux/include/classmap.h +++ b/security/selinux/include/classmap.h @@ -243,8 +243,6 @@ struct security_class_mapping secclass_map[] = { {"map_create", "map_read", "map_write", "prog_load", "prog_run"} }, { "xdp_socket", { COMMON_SOCK_PERMS, NULL } }, - { "perf_event", - {"open", "cpu", "kernel", "tracepoint", "read", "write"} }, { NULL } }; diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h index 25b69dc17d1b..cc5e26b0161b 100644 --- a/security/selinux/include/objsec.h +++ b/security/selinux/include/objsec.h @@ -155,11 +155,7 @@ struct pkey_security_struct { }; struct bpf_security_struct { - u32 sid; /* SID of bpf obj creator */ -}; - -struct perf_event_security_struct { - u32 sid; /* SID of perf_event obj creator */ + u32 sid; /*SID of bpf obj creater*/ }; #endif /* _SELINUX_OBJSEC_H_ */