diff options
Diffstat (limited to 'kernel/events')
-rw-r--r-- | kernel/events/core.c | 68 |
1 files changed, 68 insertions, 0 deletions
diff --git a/kernel/events/core.c b/kernel/events/core.c index e8b32ac75ce3..5820efdf47cd 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c | |||
@@ -118,6 +118,13 @@ static int cpu_function_call(int cpu, int (*func) (void *info), void *info) | |||
118 | PERF_FLAG_FD_OUTPUT |\ | 118 | PERF_FLAG_FD_OUTPUT |\ |
119 | PERF_FLAG_PID_CGROUP) | 119 | PERF_FLAG_PID_CGROUP) |
120 | 120 | ||
121 | /* | ||
122 | * branch priv levels that need permission checks | ||
123 | */ | ||
124 | #define PERF_SAMPLE_BRANCH_PERM_PLM \ | ||
125 | (PERF_SAMPLE_BRANCH_KERNEL |\ | ||
126 | PERF_SAMPLE_BRANCH_HV) | ||
127 | |||
121 | enum event_type_t { | 128 | enum event_type_t { |
122 | EVENT_FLEXIBLE = 0x1, | 129 | EVENT_FLEXIBLE = 0x1, |
123 | EVENT_PINNED = 0x2, | 130 | EVENT_PINNED = 0x2, |
@@ -3907,6 +3914,24 @@ void perf_output_sample(struct perf_output_handle *handle, | |||
3907 | } | 3914 | } |
3908 | } | 3915 | } |
3909 | } | 3916 | } |
3917 | |||
3918 | if (sample_type & PERF_SAMPLE_BRANCH_STACK) { | ||
3919 | if (data->br_stack) { | ||
3920 | size_t size; | ||
3921 | |||
3922 | size = data->br_stack->nr | ||
3923 | * sizeof(struct perf_branch_entry); | ||
3924 | |||
3925 | perf_output_put(handle, data->br_stack->nr); | ||
3926 | perf_output_copy(handle, data->br_stack->entries, size); | ||
3927 | } else { | ||
3928 | /* | ||
3929 | * we always store at least the value of nr | ||
3930 | */ | ||
3931 | u64 nr = 0; | ||
3932 | perf_output_put(handle, nr); | ||
3933 | } | ||
3934 | } | ||
3910 | } | 3935 | } |
3911 | 3936 | ||
3912 | void perf_prepare_sample(struct perf_event_header *header, | 3937 | void perf_prepare_sample(struct perf_event_header *header, |
@@ -3949,6 +3974,15 @@ void perf_prepare_sample(struct perf_event_header *header, | |||
3949 | WARN_ON_ONCE(size & (sizeof(u64)-1)); | 3974 | WARN_ON_ONCE(size & (sizeof(u64)-1)); |
3950 | header->size += size; | 3975 | header->size += size; |
3951 | } | 3976 | } |
3977 | |||
3978 | if (sample_type & PERF_SAMPLE_BRANCH_STACK) { | ||
3979 | int size = sizeof(u64); /* nr */ | ||
3980 | if (data->br_stack) { | ||
3981 | size += data->br_stack->nr | ||
3982 | * sizeof(struct perf_branch_entry); | ||
3983 | } | ||
3984 | header->size += size; | ||
3985 | } | ||
3952 | } | 3986 | } |
3953 | 3987 | ||
3954 | static void perf_event_output(struct perf_event *event, | 3988 | static void perf_event_output(struct perf_event *event, |
@@ -5935,6 +5969,40 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr, | |||
5935 | if (attr->read_format & ~(PERF_FORMAT_MAX-1)) | 5969 | if (attr->read_format & ~(PERF_FORMAT_MAX-1)) |
5936 | return -EINVAL; | 5970 | return -EINVAL; |
5937 | 5971 | ||
5972 | if (attr->sample_type & PERF_SAMPLE_BRANCH_STACK) { | ||
5973 | u64 mask = attr->branch_sample_type; | ||
5974 | |||
5975 | /* only using defined bits */ | ||
5976 | if (mask & ~(PERF_SAMPLE_BRANCH_MAX-1)) | ||
5977 | return -EINVAL; | ||
5978 | |||
5979 | /* at least one branch bit must be set */ | ||
5980 | if (!(mask & ~PERF_SAMPLE_BRANCH_PLM_ALL)) | ||
5981 | return -EINVAL; | ||
5982 | |||
5983 | /* kernel level capture: check permissions */ | ||
5984 | if ((mask & PERF_SAMPLE_BRANCH_PERM_PLM) | ||
5985 | && perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) | ||
5986 | return -EACCES; | ||
5987 | |||
5988 | /* propagate priv level, when not set for branch */ | ||
5989 | if (!(mask & PERF_SAMPLE_BRANCH_PLM_ALL)) { | ||
5990 | |||
5991 | /* exclude_kernel checked on syscall entry */ | ||
5992 | if (!attr->exclude_kernel) | ||
5993 | mask |= PERF_SAMPLE_BRANCH_KERNEL; | ||
5994 | |||
5995 | if (!attr->exclude_user) | ||
5996 | mask |= PERF_SAMPLE_BRANCH_USER; | ||
5997 | |||
5998 | if (!attr->exclude_hv) | ||
5999 | mask |= PERF_SAMPLE_BRANCH_HV; | ||
6000 | /* | ||
6001 | * adjust user setting (for HW filter setup) | ||
6002 | */ | ||
6003 | attr->branch_sample_type = mask; | ||
6004 | } | ||
6005 | } | ||
5938 | out: | 6006 | out: |
5939 | return ret; | 6007 | return ret; |
5940 | 6008 | ||