perf, x86: Robustify PEBS fixup
[safe/jmp/linux-2.6] / arch / x86 / kernel / cpu / perf_event_intel_ds.c
index a67fff1..e7ac517 100644 (file)
@@ -399,10 +399,23 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
        if (!x86_pmu.intel_cap.pebs_trap)
                return 1;
 
+       /*
+        * No LBR entry, no basic block, no rewinding
+        */
        if (!cpuc->lbr_stack.nr || !from || !to)
                return 0;
 
-       if (ip < to)
+       /*
+        * Basic blocks should never cross user/kernel boundaries
+        */
+       if (kernel_ip(ip) != kernel_ip(to))
+               return 0;
+
+       /*
+        * unsigned math, either ip is before the start (impossible) or
+        * the basic block is larger than 1 page (sanity)
+        */
+       if ((ip - to) > PAGE_SIZE)
                return 0;
 
        /*
@@ -420,7 +433,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
 
                old_to = to;
                if (!kernel_ip(ip)) {
-                       int bytes, size = min_t(int, MAX_INSN_SIZE, ip - to);
+                       int bytes, size = MAX_INSN_SIZE;
 
                        bytes = copy_from_user_nmi(buf, (void __user *)to, size);
                        if (bytes != size)
@@ -440,6 +453,10 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
                return 1;
        }
 
+       /*
+        * Even though we decoded the basic block, the instruction stream
+        * never matched the given IP, either the TO or the IP got corrupted.
+        */
        return 0;
 }