x86: Remove arbitrary instruction size limit in instruction decoder
[cascardo/linux.git] / arch / x86 / kernel / cpu / perf_event_intel_ds.c
index 46211bc..6a94277 100644 (file)
@@ -724,6 +724,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
        unsigned long ip = regs->ip;
        int is_64bit = 0;
        void *kaddr;
+       int size;
 
        /*
         * We don't need to fixup if the PEBS assist is fault like
@@ -758,11 +759,12 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
                return 1;
        }
 
+       size = ip - to;
        if (!kernel_ip(ip)) {
-               int size, bytes;
+               int bytes;
                u8 *buf = this_cpu_read(insn_buffer);
 
-               size = ip - to; /* Must fit our buffer, see above */
+               /* 'size' must fit our buffer, see above */
                bytes = copy_from_user_nmi(buf, (void __user *)to, size);
                if (bytes != 0)
                        return 0;
@@ -780,11 +782,20 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
 #ifdef CONFIG_X86_64
                is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32);
 #endif
-               insn_init(&insn, kaddr, is_64bit);
+               insn_init(&insn, kaddr, size, is_64bit);
                insn_get_length(&insn);
+               /*
+                * Make sure there was not a problem decoding the
+                * instruction and getting the length.  This is
+                * doubly important because we have an infinite
+                * loop if insn.length=0.
+                */
+               if (!insn.length)
+                       break;
 
                to += insn.length;
                kaddr += insn.length;
+               size -= insn.length;
        } while (to < ip);
 
        if (to == ip) {