|
@@ -21,17 +21,46 @@ typedef typeof(unsigned long [PERF_MAX_TRACE_SIZE / sizeof(unsigned long)])
|
|
|
/* Count the events in use (per event id, not per instance) */
|
|
|
static int total_ref_count;
|
|
|
|
|
|
+static int perf_trace_event_perm(struct ftrace_event_call *tp_event,
|
|
|
+ struct perf_event *p_event)
|
|
|
+{
|
|
|
+ /* No tracing, just counting, so no obvious leak */
|
|
|
+ if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* Some events are ok to be traced by non-root users... */
|
|
|
+ if (p_event->attach_state == PERF_ATTACH_TASK) {
|
|
|
+ if (tp_event->flags & TRACE_EVENT_FL_CAP_ANY)
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * ...otherwise raw tracepoint data can be a severe data leak,
|
|
|
+ * only allow root to have these.
|
|
|
+ */
|
|
|
+ if (perf_paranoid_tracepoint_raw() && !capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int perf_trace_event_init(struct ftrace_event_call *tp_event,
|
|
|
struct perf_event *p_event)
|
|
|
{
|
|
|
struct hlist_head __percpu *list;
|
|
|
- int ret = -ENOMEM;
|
|
|
+ int ret;
|
|
|
int cpu;
|
|
|
|
|
|
+ ret = perf_trace_event_perm(tp_event, p_event);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
p_event->tp_event = tp_event;
|
|
|
if (tp_event->perf_refcount++ > 0)
|
|
|
return 0;
|
|
|
|
|
|
+ ret = -ENOMEM;
|
|
|
+
|
|
|
list = alloc_percpu(struct hlist_head);
|
|
|
if (!list)
|
|
|
goto fail;
|