]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
ARM: probes: avoid adding kprobes to sensitive kernel-entry/exit code
authorRussell King <rmk+kernel@armlinux.org.uk>
Fri, 24 Nov 2017 23:54:22 +0000 (23:54 +0000)
committerRussell King <rmk+kernel@armlinux.org.uk>
Sun, 17 Dec 2017 22:14:21 +0000 (22:14 +0000)
Avoid adding kprobes to any of the kernel entry/exit or startup
assembly code, or code in the identity-mapped region.  This code does
not conform to the standard C conventions, which means that the
expectations of the kprobes code is not forfilled.

Placing kprobes at some of these locations results in the kernel trying
to return to userspace addresses while retaining the CPU in kernel mode.

Tested-by: Naresh Kamboju <naresh.kamboju@linaro.org>
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
arch/arm/include/asm/exception.h
arch/arm/include/asm/sections.h
arch/arm/include/asm/traps.h
arch/arm/kernel/entry-armv.S
arch/arm/kernel/entry-common.S
arch/arm/kernel/stacktrace.c
arch/arm/kernel/traps.c
arch/arm/kernel/vmlinux-xip.lds.S
arch/arm/kernel/vmlinux.lds.S
arch/arm/mm/fault.c
arch/arm/probes/kprobes/core.c

index a7273ad9587a2d323bd794c54bf22efc9893fa4b..58e039a851af03400dcbf23efe49cc2f0deb67ef 100644 (file)
 
 #include <linux/interrupt.h>
 
-#define __exception    __attribute__((section(".exception.text")))
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 #define __exception_irq_entry  __irq_entry
 #else
-#define __exception_irq_entry  __exception
+#define __exception_irq_entry
 #endif
 
 #endif /* __ASM_ARM_EXCEPTION_H */
index 63dfe1f103350f174975089d735393420f9973a6..4ceb4f757d4dc2c296b518ca570bc8e9fa9f9fd0 100644 (file)
@@ -6,4 +6,25 @@
 
 extern char _exiprom[];
 
+extern char __idmap_text_start[];
+extern char __idmap_text_end[];
+extern char __entry_text_start[];
+extern char __entry_text_end[];
+extern char __hyp_idmap_text_start[];
+extern char __hyp_idmap_text_end[];
+
+static inline bool in_entry_text(unsigned long addr)
+{
+       return memory_contains(__entry_text_start, __entry_text_end,
+                              (void *)addr, 1);
+}
+
+static inline bool in_idmap_text(unsigned long addr)
+{
+       void *a = (void *)addr;
+       return memory_contains(__idmap_text_start, __idmap_text_end, a, 1) ||
+              memory_contains(__hyp_idmap_text_start, __hyp_idmap_text_end,
+                              a, 1);
+}
+
 #endif /* _ASM_ARM_SECTIONS_H */
index f9a6c5fc3fd14c8fa00de21f00ff018ddfa39592..a00288d75ee6ad7349d7813a8691b77c2a1ca7ec 100644 (file)
@@ -28,18 +28,6 @@ static inline int __in_irqentry_text(unsigned long ptr)
               ptr < (unsigned long)&__irqentry_text_end;
 }
 
-static inline int in_exception_text(unsigned long ptr)
-{
-       extern char __exception_text_start[];
-       extern char __exception_text_end[];
-       int in;
-
-       in = ptr >= (unsigned long)&__exception_text_start &&
-            ptr < (unsigned long)&__exception_text_end;
-
-       return in ? : __in_irqentry_text(ptr);
-}
-
 extern void __init early_trap_init(void *);
 extern void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long frame);
 extern void ptrace_break(struct task_struct *tsk, struct pt_regs *regs);
index fbc707626b3e9e6794400e41ba1b08916cdf8d4a..1752033b00700c780666352d6b256f5d36396d28 100644 (file)
 #endif
        .endm
 
-#ifdef CONFIG_KPROBES
-       .section        .kprobes.text,"ax",%progbits
-#else
-       .text
-#endif
+       .section        .entry.text,"ax",%progbits
 
 /*
  * Invalid mode handlers
index e655dcd0a933c7e293c800facfdbd44f66154098..3c4f88701f224984bfb5fecaf304d96918b56548 100644 (file)
@@ -37,6 +37,7 @@ saved_pc      .req    lr
 #define TRACE(x...)
 #endif
 
+       .section .entry.text,"ax",%progbits
        .align  5
 #if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING))
 /*
index 65228bf4c6dfee221e4e3a38112c0d59ecda65f9..a56e7c856ab5648995888ae5f47c5d1ab23b08bf 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/sched/debug.h>
 #include <linux/stacktrace.h>
 
+#include <asm/sections.h>
 #include <asm/stacktrace.h>
 #include <asm/traps.h>
 
@@ -63,7 +64,6 @@ EXPORT_SYMBOL(walk_stackframe);
 #ifdef CONFIG_STACKTRACE
 struct stack_trace_data {
        struct stack_trace *trace;
-       unsigned long last_pc;
        unsigned int no_sched_functions;
        unsigned int skip;
 };
@@ -87,16 +87,7 @@ static int save_trace(struct stackframe *frame, void *d)
        if (trace->nr_entries >= trace->max_entries)
                return 1;
 
-       /*
-        * in_exception_text() is designed to test if the PC is one of
-        * the functions which has an exception stack above it, but
-        * unfortunately what is in frame->pc is the return LR value,
-        * not the saved PC value.  So, we need to track the previous
-        * frame PC value when doing this.
-        */
-       addr = data->last_pc;
-       data->last_pc = frame->pc;
-       if (!in_exception_text(addr))
+       if (!in_entry_text(frame->pc))
                return 0;
 
        regs = (struct pt_regs *)frame->sp;
@@ -114,7 +105,6 @@ static noinline void __save_stack_trace(struct task_struct *tsk,
        struct stackframe frame;
 
        data.trace = trace;
-       data.last_pc = ULONG_MAX;
        data.skip = trace->skip;
        data.no_sched_functions = nosched;
 
index 5cf04888c581df4a21053a826f8a2fdd58204435..e344bdd2e5acd4913dc1aec94b199bd0d0cd1c9d 100644 (file)
@@ -72,7 +72,7 @@ void dump_backtrace_entry(unsigned long where, unsigned long from, unsigned long
        printk("Function entered at [<%08lx>] from [<%08lx>]\n", where, from);
 #endif
 
-       if (in_exception_text(where))
+       if (in_entry_text(from))
                dump_mem("", "Exception stack", frame + 4, frame + 4 + sizeof(struct pt_regs));
 }
 
@@ -433,7 +433,7 @@ static int call_undef_hook(struct pt_regs *regs, unsigned int instr)
        return fn ? fn(regs, instr) : 1;
 }
 
-asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
+asmlinkage void do_undefinstr(struct pt_regs *regs)
 {
        unsigned int instr;
        siginfo_t info;
index ec4b3f94ad8071e779974dbd55f7843af175df3d..12b87591eb7ce2c267ec9d9065366d795af61460 100644 (file)
@@ -96,9 +96,9 @@ SECTIONS
        .text : {                       /* Real text segment            */
                _stext = .;             /* Text and read-only data      */
                        IDMAP_TEXT
-                       __exception_text_start = .;
-                       *(.exception.text)
-                       __exception_text_end = .;
+                       __entry_text_start = .;
+                       *(.entry.text)
+                       __entry_text_end = .;
                        IRQENTRY_TEXT
                        TEXT_TEXT
                        SCHED_TEXT
index ee53f65188724b07c517d36a8bb0763d3b5acf17..84a1ae3ce46e24ad19d2003a9e339c18644a3f0b 100644 (file)
@@ -105,9 +105,9 @@ SECTIONS
        .text : {                       /* Real text segment            */
                _stext = .;             /* Text and read-only data      */
                        IDMAP_TEXT
-                       __exception_text_start = .;
-                       *(.exception.text)
-                       __exception_text_end = .;
+                       __entry_text_start = .;
+                       *(.entry.text)
+                       __entry_text_end = .;
                        IRQENTRY_TEXT
                        SOFTIRQENTRY_TEXT
                        TEXT_TEXT
index 42f585379e19c97fcb6abe1004d9b469f90215ce..b75eada23d0a3be3e635b612adb431e5c06e34ef 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/highmem.h>
 #include <linux/perf_event.h>
 
-#include <asm/exception.h>
 #include <asm/pgtable.h>
 #include <asm/system_misc.h>
 #include <asm/system_info.h>
@@ -545,7 +544,7 @@ hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *)
 /*
  * Dispatch a data abort to the relevant handler.
  */
-asmlinkage void __exception
+asmlinkage void
 do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
 {
        const struct fsr_info *inf = fsr_info + fsr_fs(fsr);
@@ -578,7 +577,7 @@ hook_ifault_code(int nr, int (*fn)(unsigned long, unsigned int, struct pt_regs *
        ifsr_info[nr].name = name;
 }
 
-asmlinkage void __exception
+asmlinkage void
 do_PrefetchAbort(unsigned long addr, unsigned int ifsr, struct pt_regs *regs)
 {
        const struct fsr_info *inf = ifsr_info + fsr_fs(ifsr);
index 52d1cd14fda45d961ece2d0c4d417d986a372de9..e90cc8a08186c03af0cd44827d4b77e978436f90 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/percpu.h>
 #include <linux/bug.h>
 #include <asm/patch.h>
+#include <asm/sections.h>
 
 #include "../decode-arm.h"
 #include "../decode-thumb.h"
@@ -64,9 +65,6 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p)
        int is;
        const struct decode_checker **checkers;
 
-       if (in_exception_text(addr))
-               return -EINVAL;
-
 #ifdef CONFIG_THUMB2_KERNEL
        thumb = true;
        addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
@@ -680,3 +678,13 @@ int __init arch_init_kprobes()
 #endif
        return 0;
 }
+
+bool arch_within_kprobe_blacklist(unsigned long addr)
+{
+       void *a = (void *)addr;
+
+       return __in_irqentry_text(addr) ||
+              in_entry_text(addr) ||
+              in_idmap_text(addr) ||
+              memory_contains(__kprobes_text_start, __kprobes_text_end, a, 1);
+}