diff options
author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2014-04-17 04:17:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2014-04-24 04:02:56 -0400 |
commit | 376e242429bf8539ef39a080ac113c8799840b13 (patch) | |
tree | 33c871f48d37acd167de0b3bf5c902ce4aaa325c | |
parent | be8f274323c26ddc7e6fd6c44254b7abcdbe6389 (diff) |
kprobes: Introduce NOKPROBE_SYMBOL() macro to maintain kprobes blacklist
Introduce NOKPROBE_SYMBOL() macro which builds a kprobes
blacklist at kernel build time.
The usage of this macro is similar to EXPORT_SYMBOL(),
placed after the function definition:
NOKPROBE_SYMBOL(function);
Since this macro will inhibit inlining of static/inline
functions, this patch also introduces a nokprobe_inline macro
for static/inline functions. In this case, we must use
NOKPROBE_SYMBOL() for the inline function caller.
When CONFIG_KPROBES=y, the macro stores the given function
address in the "_kprobe_blacklist" section.
Since the data structures are not fully initialized by the
macro (because there is no "size" information), those
are re-initialized at boot time by using kallsyms.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Link: http://lkml.kernel.org/r/20140417081705.26341.96719.stgit@ltc230.yrl.intra.hitachi.co.jp
Cc: Alok Kataria <akataria@vmware.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Christopher Li <sparse@chrisli.org>
Cc: Chris Wright <chrisw@sous-sol.org>
Cc: David S. Miller <davem@davemloft.net>
Cc: Jan-Simon Möller <dl9pf@gmx.de>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Randy Dunlap <rdunlap@infradead.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: linux-arch@vger.kernel.org
Cc: linux-doc@vger.kernel.org
Cc: linux-sparse@vger.kernel.org
Cc: virtualization@lists.linux-foundation.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | Documentation/kprobes.txt | 16 | ||||
-rw-r--r-- | arch/x86/include/asm/asm.h | 7 | ||||
-rw-r--r-- | arch/x86/kernel/paravirt.c | 4 | ||||
-rw-r--r-- | include/asm-generic/vmlinux.lds.h | 9 | ||||
-rw-r--r-- | include/linux/compiler.h | 2 | ||||
-rw-r--r-- | include/linux/kprobes.h | 20 | ||||
-rw-r--r-- | kernel/kprobes.c | 100 | ||||
-rw-r--r-- | kernel/sched/core.c | 1 |
8 files changed, 107 insertions, 52 deletions
diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 0cfb00fd86ff..4bbeca8483ed 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt | |||
@@ -22,8 +22,9 @@ Appendix B: The kprobes sysctl interface | |||
22 | 22 | ||
23 | Kprobes enables you to dynamically break into any kernel routine and | 23 | Kprobes enables you to dynamically break into any kernel routine and |
24 | collect debugging and performance information non-disruptively. You | 24 | collect debugging and performance information non-disruptively. You |
25 | can trap at almost any kernel code address, specifying a handler | 25 | can trap at almost any kernel code address(*), specifying a handler |
26 | routine to be invoked when the breakpoint is hit. | 26 | routine to be invoked when the breakpoint is hit. |
27 | (*: some parts of the kernel code can not be trapped, see 1.5 Blacklist) | ||
27 | 28 | ||
28 | There are currently three types of probes: kprobes, jprobes, and | 29 | There are currently three types of probes: kprobes, jprobes, and |
29 | kretprobes (also called return probes). A kprobe can be inserted | 30 | kretprobes (also called return probes). A kprobe can be inserted |
@@ -273,6 +274,19 @@ using one of the following techniques: | |||
273 | or | 274 | or |
274 | - Execute 'sysctl -w debug.kprobes_optimization=n' | 275 | - Execute 'sysctl -w debug.kprobes_optimization=n' |
275 | 276 | ||
277 | 1.5 Blacklist | ||
278 | |||
279 | Kprobes can probe most of the kernel except itself. This means | ||
280 | that there are some functions where kprobes cannot probe. Probing | ||
281 | (trapping) such functions can cause a recursive trap (e.g. double | ||
282 | fault) or the nested probe handler may never be called. | ||
283 | Kprobes manages such functions as a blacklist. | ||
284 | If you want to add a function into the blacklist, you just need | ||
285 | to (1) include linux/kprobes.h and (2) use NOKPROBE_SYMBOL() macro | ||
286 | to specify a blacklisted function. | ||
287 | Kprobes checks the given probe address against the blacklist and | ||
288 | rejects registering it, if the given address is in the blacklist. | ||
289 | |||
276 | 2. Architectures Supported | 290 | 2. Architectures Supported |
277 | 291 | ||
278 | Kprobes, jprobes, and return probes are implemented on the following | 292 | Kprobes, jprobes, and return probes are implemented on the following |
diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 4582e8e1cd1a..7730c1c5c83a 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h | |||
@@ -57,6 +57,12 @@ | |||
57 | .long (from) - . ; \ | 57 | .long (from) - . ; \ |
58 | .long (to) - . + 0x7ffffff0 ; \ | 58 | .long (to) - . + 0x7ffffff0 ; \ |
59 | .popsection | 59 | .popsection |
60 | |||
61 | # define _ASM_NOKPROBE(entry) \ | ||
62 | .pushsection "_kprobe_blacklist","aw" ; \ | ||
63 | _ASM_ALIGN ; \ | ||
64 | _ASM_PTR (entry); \ | ||
65 | .popsection | ||
60 | #else | 66 | #else |
61 | # define _ASM_EXTABLE(from,to) \ | 67 | # define _ASM_EXTABLE(from,to) \ |
62 | " .pushsection \"__ex_table\",\"a\"\n" \ | 68 | " .pushsection \"__ex_table\",\"a\"\n" \ |
@@ -71,6 +77,7 @@ | |||
71 | " .long (" #from ") - .\n" \ | 77 | " .long (" #from ") - .\n" \ |
72 | " .long (" #to ") - . + 0x7ffffff0\n" \ | 78 | " .long (" #to ") - . + 0x7ffffff0\n" \ |
73 | " .popsection\n" | 79 | " .popsection\n" |
80 | /* For C file, we already have NOKPROBE_SYMBOL macro */ | ||
74 | #endif | 81 | #endif |
75 | 82 | ||
76 | #endif /* _ASM_X86_ASM_H */ | 83 | #endif /* _ASM_X86_ASM_H */ |
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c index 1b10af835c31..e136869ae42e 100644 --- a/arch/x86/kernel/paravirt.c +++ b/arch/x86/kernel/paravirt.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/efi.h> | 23 | #include <linux/efi.h> |
24 | #include <linux/bcd.h> | 24 | #include <linux/bcd.h> |
25 | #include <linux/highmem.h> | 25 | #include <linux/highmem.h> |
26 | #include <linux/kprobes.h> | ||
26 | 27 | ||
27 | #include <asm/bug.h> | 28 | #include <asm/bug.h> |
28 | #include <asm/paravirt.h> | 29 | #include <asm/paravirt.h> |
@@ -389,6 +390,9 @@ __visible struct pv_cpu_ops pv_cpu_ops = { | |||
389 | .end_context_switch = paravirt_nop, | 390 | .end_context_switch = paravirt_nop, |
390 | }; | 391 | }; |
391 | 392 | ||
393 | /* At this point, native_get_debugreg has a real function entry */ | ||
394 | NOKPROBE_SYMBOL(native_get_debugreg); | ||
395 | |||
392 | struct pv_apic_ops pv_apic_ops = { | 396 | struct pv_apic_ops pv_apic_ops = { |
393 | #ifdef CONFIG_X86_LOCAL_APIC | 397 | #ifdef CONFIG_X86_LOCAL_APIC |
394 | .startup_ipi_hook = paravirt_nop, | 398 | .startup_ipi_hook = paravirt_nop, |
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 146e4fffd710..40ceb3ceba79 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h | |||
@@ -109,6 +109,14 @@ | |||
109 | #define BRANCH_PROFILE() | 109 | #define BRANCH_PROFILE() |
110 | #endif | 110 | #endif |
111 | 111 | ||
112 | #ifdef CONFIG_KPROBES | ||
113 | #define KPROBE_BLACKLIST() VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \ | ||
114 | *(_kprobe_blacklist) \ | ||
115 | VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .; | ||
116 | #else | ||
117 | #define KPROBE_BLACKLIST() | ||
118 | #endif | ||
119 | |||
112 | #ifdef CONFIG_EVENT_TRACING | 120 | #ifdef CONFIG_EVENT_TRACING |
113 | #define FTRACE_EVENTS() . = ALIGN(8); \ | 121 | #define FTRACE_EVENTS() . = ALIGN(8); \ |
114 | VMLINUX_SYMBOL(__start_ftrace_events) = .; \ | 122 | VMLINUX_SYMBOL(__start_ftrace_events) = .; \ |
@@ -507,6 +515,7 @@ | |||
507 | *(.init.rodata) \ | 515 | *(.init.rodata) \ |
508 | FTRACE_EVENTS() \ | 516 | FTRACE_EVENTS() \ |
509 | TRACE_SYSCALLS() \ | 517 | TRACE_SYSCALLS() \ |
518 | KPROBE_BLACKLIST() \ | ||
510 | MEM_DISCARD(init.rodata) \ | 519 | MEM_DISCARD(init.rodata) \ |
511 | CLK_OF_TABLES() \ | 520 | CLK_OF_TABLES() \ |
512 | RESERVEDMEM_OF_TABLES() \ | 521 | RESERVEDMEM_OF_TABLES() \ |
diff --git a/include/linux/compiler.h b/include/linux/compiler.h index ee7239ea1583..0300c0f5c88b 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h | |||
@@ -374,7 +374,9 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); | |||
374 | /* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */ | 374 | /* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */ |
375 | #ifdef CONFIG_KPROBES | 375 | #ifdef CONFIG_KPROBES |
376 | # define __kprobes __attribute__((__section__(".kprobes.text"))) | 376 | # define __kprobes __attribute__((__section__(".kprobes.text"))) |
377 | # define nokprobe_inline __always_inline | ||
377 | #else | 378 | #else |
378 | # define __kprobes | 379 | # define __kprobes |
380 | # define nokprobe_inline inline | ||
379 | #endif | 381 | #endif |
380 | #endif /* __LINUX_COMPILER_H */ | 382 | #endif /* __LINUX_COMPILER_H */ |
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index cdf9251f8249..e059507c465d 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
@@ -205,10 +205,10 @@ struct kretprobe_blackpoint { | |||
205 | void *addr; | 205 | void *addr; |
206 | }; | 206 | }; |
207 | 207 | ||
208 | struct kprobe_blackpoint { | 208 | struct kprobe_blacklist_entry { |
209 | const char *name; | 209 | struct list_head list; |
210 | unsigned long start_addr; | 210 | unsigned long start_addr; |
211 | unsigned long range; | 211 | unsigned long end_addr; |
212 | }; | 212 | }; |
213 | 213 | ||
214 | #ifdef CONFIG_KPROBES | 214 | #ifdef CONFIG_KPROBES |
@@ -477,4 +477,18 @@ static inline int enable_jprobe(struct jprobe *jp) | |||
477 | return enable_kprobe(&jp->kp); | 477 | return enable_kprobe(&jp->kp); |
478 | } | 478 | } |
479 | 479 | ||
480 | #ifdef CONFIG_KPROBES | ||
481 | /* | ||
482 | * Blacklist ganerating macro. Specify functions which is not probed | ||
483 | * by using this macro. | ||
484 | */ | ||
485 | #define __NOKPROBE_SYMBOL(fname) \ | ||
486 | static unsigned long __used \ | ||
487 | __attribute__((section("_kprobe_blacklist"))) \ | ||
488 | _kbl_addr_##fname = (unsigned long)fname; | ||
489 | #define NOKPROBE_SYMBOL(fname) __NOKPROBE_SYMBOL(fname) | ||
490 | #else | ||
491 | #define NOKPROBE_SYMBOL(fname) | ||
492 | #endif | ||
493 | |||
480 | #endif /* _LINUX_KPROBES_H */ | 494 | #endif /* _LINUX_KPROBES_H */ |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 5b5ac76671e7..5ffc6875d2a7 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
@@ -86,18 +86,8 @@ static raw_spinlock_t *kretprobe_table_lock_ptr(unsigned long hash) | |||
86 | return &(kretprobe_table_locks[hash].lock); | 86 | return &(kretprobe_table_locks[hash].lock); |
87 | } | 87 | } |
88 | 88 | ||
89 | /* | 89 | /* Blacklist -- list of struct kprobe_blacklist_entry */ |
90 | * Normally, functions that we'd want to prohibit kprobes in, are marked | 90 | static LIST_HEAD(kprobe_blacklist); |
91 | * __kprobes. But, there are cases where such functions already belong to | ||
92 | * a different section (__sched for preempt_schedule) | ||
93 | * | ||
94 | * For such cases, we now have a blacklist | ||
95 | */ | ||
96 | static struct kprobe_blackpoint kprobe_blacklist[] = { | ||
97 | {"preempt_schedule",}, | ||
98 | {"native_get_debugreg",}, | ||
99 | {NULL} /* Terminator */ | ||
100 | }; | ||
101 | 91 | ||
102 | #ifdef __ARCH_WANT_KPROBES_INSN_SLOT | 92 | #ifdef __ARCH_WANT_KPROBES_INSN_SLOT |
103 | /* | 93 | /* |
@@ -1328,24 +1318,22 @@ bool __weak arch_within_kprobe_blacklist(unsigned long addr) | |||
1328 | addr < (unsigned long)__kprobes_text_end; | 1318 | addr < (unsigned long)__kprobes_text_end; |
1329 | } | 1319 | } |
1330 | 1320 | ||
1331 | static int __kprobes in_kprobes_functions(unsigned long addr) | 1321 | static bool __kprobes within_kprobe_blacklist(unsigned long addr) |
1332 | { | 1322 | { |
1333 | struct kprobe_blackpoint *kb; | 1323 | struct kprobe_blacklist_entry *ent; |
1334 | 1324 | ||
1335 | if (arch_within_kprobe_blacklist(addr)) | 1325 | if (arch_within_kprobe_blacklist(addr)) |
1336 | return -EINVAL; | 1326 | return true; |
1337 | /* | 1327 | /* |
1338 | * If there exists a kprobe_blacklist, verify and | 1328 | * If there exists a kprobe_blacklist, verify and |
1339 | * fail any probe registration in the prohibited area | 1329 | * fail any probe registration in the prohibited area |
1340 | */ | 1330 | */ |
1341 | for (kb = kprobe_blacklist; kb->name != NULL; kb++) { | 1331 | list_for_each_entry(ent, &kprobe_blacklist, list) { |
1342 | if (kb->start_addr) { | 1332 | if (addr >= ent->start_addr && addr < ent->end_addr) |
1343 | if (addr >= kb->start_addr && | 1333 | return true; |
1344 | addr < (kb->start_addr + kb->range)) | ||
1345 | return -EINVAL; | ||
1346 | } | ||
1347 | } | 1334 | } |
1348 | return 0; | 1335 | |
1336 | return false; | ||
1349 | } | 1337 | } |
1350 | 1338 | ||
1351 | /* | 1339 | /* |
@@ -1436,7 +1424,7 @@ static __kprobes int check_kprobe_address_safe(struct kprobe *p, | |||
1436 | 1424 | ||
1437 | /* Ensure it is not in reserved area nor out of text */ | 1425 | /* Ensure it is not in reserved area nor out of text */ |
1438 | if (!kernel_text_address((unsigned long) p->addr) || | 1426 | if (!kernel_text_address((unsigned long) p->addr) || |
1439 | in_kprobes_functions((unsigned long) p->addr) || | 1427 | within_kprobe_blacklist((unsigned long) p->addr) || |
1440 | jump_label_text_reserved(p->addr, p->addr)) { | 1428 | jump_label_text_reserved(p->addr, p->addr)) { |
1441 | ret = -EINVAL; | 1429 | ret = -EINVAL; |
1442 | goto out; | 1430 | goto out; |
@@ -2022,6 +2010,38 @@ void __kprobes dump_kprobe(struct kprobe *kp) | |||
2022 | kp->symbol_name, kp->addr, kp->offset); | 2010 | kp->symbol_name, kp->addr, kp->offset); |
2023 | } | 2011 | } |
2024 | 2012 | ||
2013 | /* | ||
2014 | * Lookup and populate the kprobe_blacklist. | ||
2015 | * | ||
2016 | * Unlike the kretprobe blacklist, we'll need to determine | ||
2017 | * the range of addresses that belong to the said functions, | ||
2018 | * since a kprobe need not necessarily be at the beginning | ||
2019 | * of a function. | ||
2020 | */ | ||
2021 | static int __init populate_kprobe_blacklist(unsigned long *start, | ||
2022 | unsigned long *end) | ||
2023 | { | ||
2024 | unsigned long *iter; | ||
2025 | struct kprobe_blacklist_entry *ent; | ||
2026 | unsigned long offset = 0, size = 0; | ||
2027 | |||
2028 | for (iter = start; iter < end; iter++) { | ||
2029 | if (!kallsyms_lookup_size_offset(*iter, &size, &offset)) { | ||
2030 | pr_err("Failed to find blacklist %p\n", (void *)*iter); | ||
2031 | continue; | ||
2032 | } | ||
2033 | |||
2034 | ent = kmalloc(sizeof(*ent), GFP_KERNEL); | ||
2035 | if (!ent) | ||
2036 | return -ENOMEM; | ||
2037 | ent->start_addr = *iter; | ||
2038 | ent->end_addr = *iter + size; | ||
2039 | INIT_LIST_HEAD(&ent->list); | ||
2040 | list_add_tail(&ent->list, &kprobe_blacklist); | ||
2041 | } | ||
2042 | return 0; | ||
2043 | } | ||
2044 | |||
2025 | /* Module notifier call back, checking kprobes on the module */ | 2045 | /* Module notifier call back, checking kprobes on the module */ |
2026 | static int __kprobes kprobes_module_callback(struct notifier_block *nb, | 2046 | static int __kprobes kprobes_module_callback(struct notifier_block *nb, |
2027 | unsigned long val, void *data) | 2047 | unsigned long val, void *data) |
@@ -2065,14 +2085,13 @@ static struct notifier_block kprobe_module_nb = { | |||
2065 | .priority = 0 | 2085 | .priority = 0 |
2066 | }; | 2086 | }; |
2067 | 2087 | ||
2088 | /* Markers of _kprobe_blacklist section */ | ||
2089 | extern unsigned long __start_kprobe_blacklist[]; | ||
2090 | extern unsigned long __stop_kprobe_blacklist[]; | ||
2091 | |||
2068 | static int __init init_kprobes(void) | 2092 | static int __init init_kprobes(void) |
2069 | { | 2093 | { |
2070 | int i, err = 0; | 2094 | int i, err = 0; |
2071 | unsigned long offset = 0, size = 0; | ||
2072 | char *modname, namebuf[KSYM_NAME_LEN]; | ||
2073 | const char *symbol_name; | ||
2074 | void *addr; | ||
2075 | struct kprobe_blackpoint *kb; | ||
2076 | 2095 | ||
2077 | /* FIXME allocate the probe table, currently defined statically */ | 2096 | /* FIXME allocate the probe table, currently defined statically */ |
2078 | /* initialize all list heads */ | 2097 | /* initialize all list heads */ |
@@ -2082,26 +2101,11 @@ static int __init init_kprobes(void) | |||
2082 | raw_spin_lock_init(&(kretprobe_table_locks[i].lock)); | 2101 | raw_spin_lock_init(&(kretprobe_table_locks[i].lock)); |
2083 | } | 2102 | } |
2084 | 2103 | ||
2085 | /* | 2104 | err = populate_kprobe_blacklist(__start_kprobe_blacklist, |
2086 | * Lookup and populate the kprobe_blacklist. | 2105 | __stop_kprobe_blacklist); |
2087 | * | 2106 | if (err) { |
2088 | * Unlike the kretprobe blacklist, we'll need to determine | 2107 | pr_err("kprobes: failed to populate blacklist: %d\n", err); |
2089 | * the range of addresses that belong to the said functions, | 2108 | pr_err("Please take care of using kprobes.\n"); |
2090 | * since a kprobe need not necessarily be at the beginning | ||
2091 | * of a function. | ||
2092 | */ | ||
2093 | for (kb = kprobe_blacklist; kb->name != NULL; kb++) { | ||
2094 | kprobe_lookup_name(kb->name, addr); | ||
2095 | if (!addr) | ||
2096 | continue; | ||
2097 | |||
2098 | kb->start_addr = (unsigned long)addr; | ||
2099 | symbol_name = kallsyms_lookup(kb->start_addr, | ||
2100 | &size, &offset, &modname, namebuf); | ||
2101 | if (!symbol_name) | ||
2102 | kb->range = 0; | ||
2103 | else | ||
2104 | kb->range = size; | ||
2105 | } | 2109 | } |
2106 | 2110 | ||
2107 | if (kretprobe_blacklist_size) { | 2111 | if (kretprobe_blacklist_size) { |
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 268a45ea238c..6863631e8cd0 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -2804,6 +2804,7 @@ asmlinkage void __sched notrace preempt_schedule(void) | |||
2804 | barrier(); | 2804 | barrier(); |
2805 | } while (need_resched()); | 2805 | } while (need_resched()); |
2806 | } | 2806 | } |
2807 | NOKPROBE_SYMBOL(preempt_schedule); | ||
2807 | EXPORT_SYMBOL(preempt_schedule); | 2808 | EXPORT_SYMBOL(preempt_schedule); |
2808 | #endif /* CONFIG_PREEMPT */ | 2809 | #endif /* CONFIG_PREEMPT */ |
2809 | 2810 | ||