]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - kernel/events/core.c
Merge branch 'perf/urgent' into perf/core, to pick up fixes
[mirror_ubuntu-artful-kernel.git] / kernel / events / core.c
index 6e75a5c9412dee17daabc1cb131bb517ad431207..3de0b98c441465976121ec6fcdbba00c7e0d8a28 100644 (file)
@@ -7316,6 +7316,21 @@ int perf_event_account_interrupt(struct perf_event *event)
        return __perf_event_account_interrupt(event, 1);
 }
 
+static bool sample_is_allowed(struct perf_event *event, struct pt_regs *regs)
+{
+       /*
+        * Due to interrupt latency (AKA "skid"), we may enter the
+        * kernel before taking an overflow, even if the PMU is only
+        * counting user events.
+        * To avoid leaking information to userspace, we must always
+        * reject kernel samples when exclude_kernel is set.
+        */
+       if (event->attr.exclude_kernel && !user_mode(regs))
+               return false;
+
+       return true;
+}
+
 /*
  * Generic event overflow handling, sampling.
  */
@@ -7336,6 +7351,12 @@ static int __perf_event_overflow(struct perf_event *event,
 
        ret = __perf_event_account_interrupt(event, throttle);
 
+       /*
+        * For security, drop the skid kernel samples if necessary.
+        */
+       if (!sample_is_allowed(event, regs))
+               return ret;
+
        /*
         * XXX event_limit might not quite work as expected on inherited
         * events
@@ -9172,7 +9193,7 @@ static int perf_try_init_event(struct pmu *pmu, struct perf_event *event)
 
 static struct pmu *perf_init_event(struct perf_event *event)
 {
-       struct pmu *pmu = NULL;
+       struct pmu *pmu;
        int idx;
        int ret;
 
@@ -9456,9 +9477,7 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
        }
 
        pmu = perf_init_event(event);
-       if (!pmu)
-               goto err_ns;
-       else if (IS_ERR(pmu)) {
+       if (IS_ERR(pmu)) {
                err = PTR_ERR(pmu);
                goto err_ns;
        }
@@ -9471,8 +9490,10 @@ perf_event_alloc(struct perf_event_attr *attr, int cpu,
                event->addr_filters_offs = kcalloc(pmu->nr_addr_filters,
                                                   sizeof(unsigned long),
                                                   GFP_KERNEL);
-               if (!event->addr_filters_offs)
+               if (!event->addr_filters_offs) {
+                       err = -ENOMEM;
                        goto err_per_task;
+               }
 
                /* force hw sync on the address filters */
                event->addr_filters_gen = 1;