perf/x86/hw_breakpoints: Disallow kernel breakpoints unless kprobe-safe
authorAndy Lutomirski <luto@kernel.org>
Fri, 31 Jul 2015 03:32:40 +0000 (20:32 -0700)
committerIngo Molnar <mingo@kernel.org>
Tue, 4 Aug 2015 08:16:54 +0000 (10:16 +0200)
Code on the kprobe blacklist doesn't want unexpected int3
exceptions. It probably doesn't want unexpected debug exceptions
either. Be safe: disallow breakpoints in nokprobes code.

On non-CONFIG_KPROBES kernels, there is no kprobe blacklist.  In
that case, disallow kernel breakpoints entirely.

It will be particularly important to keep hw breakpoints out of the
entry and NMI code once we move debug exceptions off the IST stack.

Signed-off-by: Andy Lutomirski <luto@kernel.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/e14b152af99640448d895e3c2a8c2d5ee19a1325.1438312874.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/kernel/hw_breakpoint.c
include/linux/kprobes.h
kernel/kprobes.c

index 7114ba220fd45d64cb24d86f9a3dd5c3bc65bceb..78f3e90c565927591790cadd98f5bacaa14c90a9 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/irqflags.h>
 #include <linux/notifier.h>
 #include <linux/kallsyms.h>
+#include <linux/kprobes.h>
 #include <linux/percpu.h>
 #include <linux/kdebug.h>
 #include <linux/kernel.h>
@@ -243,6 +244,20 @@ static int arch_build_bp_info(struct perf_event *bp)
                info->type = X86_BREAKPOINT_RW;
                break;
        case HW_BREAKPOINT_X:
+               /*
+                * We don't allow kernel breakpoints in places that are not
+                * acceptable for kprobes.  On non-kprobes kernels, we don't
+                * allow kernel breakpoints at all.
+                */
+               if (bp->attr.bp_addr >= TASK_SIZE_MAX) {
+#ifdef CONFIG_KPROBES
+                       if (within_kprobe_blacklist(bp->attr.bp_addr))
+                               return -EINVAL;
+#else
+                       return -EINVAL;
+#endif
+               }
+
                info->type = X86_BREAKPOINT_EXECUTE;
                /*
                 * x86 inst breakpoints need to have a specific undefined len.
index 1ab54754a86d2110c568c66da1d7abf95d66e4f2..8f68490842481286446efc92a835ff38db1f1aac 100644 (file)
@@ -267,6 +267,8 @@ extern void show_registers(struct pt_regs *regs);
 extern void kprobes_inc_nmissed_count(struct kprobe *p);
 extern bool arch_within_kprobe_blacklist(unsigned long addr);
 
+extern bool within_kprobe_blacklist(unsigned long addr);
+
 struct kprobe_insn_cache {
        struct mutex mutex;
        void *(*alloc)(void);   /* allocate insn page */
index c90e417bb9636300e4f4fe87d2c995a6c2cdab12..d10ab6b9b5e082e47570ab76b8e5aefa7e58ec5a 100644 (file)
@@ -1332,7 +1332,7 @@ bool __weak arch_within_kprobe_blacklist(unsigned long addr)
               addr < (unsigned long)__kprobes_text_end;
 }
 
-static bool within_kprobe_blacklist(unsigned long addr)
+bool within_kprobe_blacklist(unsigned long addr)
 {
        struct kprobe_blacklist_entry *ent;