diff options
| author | Masami Hiramatsu <mhiramat@kernel.org> | 2018-12-17 03:20:55 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2018-12-17 11:48:38 -0500 |
| commit | fb1a59fae8baa3f3c69b72a87ff94fc4fa5683ec (patch) | |
| tree | 273163bfcd203a75fed6c6b5e98fb56a0345d741 | |
| parent | 76aea1eeb98d2d75d9297fda777efeffe3657aeb (diff) | |
kprobes: Blacklist symbols in arch-defined prohibited area
Blacklist symbols in arch-defined probe-prohibited areas.
With this change, user can see all symbols which are prohibited
to probe in debugfs.
All archtectures which have custom prohibit areas should define
its own arch_populate_kprobe_blacklist() function, but unless that,
all symbols marked __kprobes are blacklisted.
Reported-by: Andrea Righi <righi.andrea@gmail.com>
Tested-by: Andrea Righi <righi.andrea@gmail.com>
Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
Cc: Borislav Petkov <bp@alien8.de>
Cc: David S. Miller <davem@davemloft.net>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Yonghong Song <yhs@fb.com>
Link: http://lkml.kernel.org/r/154503485491.26176.15823229545155174796.stgit@devbox
Signed-off-by: Ingo Molnar <mingo@kernel.org>
| -rw-r--r-- | include/linux/kprobes.h | 3 | ||||
| -rw-r--r-- | kernel/kprobes.c | 67 |
2 files changed, 56 insertions, 14 deletions
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h index e909413e4e38..5da8a1de2187 100644 --- a/include/linux/kprobes.h +++ b/include/linux/kprobes.h | |||
| @@ -242,10 +242,13 @@ extern int arch_init_kprobes(void); | |||
| 242 | extern void show_registers(struct pt_regs *regs); | 242 | extern void show_registers(struct pt_regs *regs); |
| 243 | extern void kprobes_inc_nmissed_count(struct kprobe *p); | 243 | extern void kprobes_inc_nmissed_count(struct kprobe *p); |
| 244 | extern bool arch_within_kprobe_blacklist(unsigned long addr); | 244 | extern bool arch_within_kprobe_blacklist(unsigned long addr); |
| 245 | extern int arch_populate_kprobe_blacklist(void); | ||
| 245 | extern bool arch_kprobe_on_func_entry(unsigned long offset); | 246 | extern bool arch_kprobe_on_func_entry(unsigned long offset); |
| 246 | extern bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset); | 247 | extern bool kprobe_on_func_entry(kprobe_opcode_t *addr, const char *sym, unsigned long offset); |
| 247 | 248 | ||
| 248 | extern bool within_kprobe_blacklist(unsigned long addr); | 249 | extern bool within_kprobe_blacklist(unsigned long addr); |
| 250 | extern int kprobe_add_ksym_blacklist(unsigned long entry); | ||
| 251 | extern int kprobe_add_area_blacklist(unsigned long start, unsigned long end); | ||
| 249 | 252 | ||
| 250 | struct kprobe_insn_cache { | 253 | struct kprobe_insn_cache { |
| 251 | struct mutex mutex; | 254 | struct mutex mutex; |
diff --git a/kernel/kprobes.c b/kernel/kprobes.c index 90e98e233647..90569aec0f24 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c | |||
| @@ -2093,6 +2093,47 @@ void dump_kprobe(struct kprobe *kp) | |||
| 2093 | } | 2093 | } |
| 2094 | NOKPROBE_SYMBOL(dump_kprobe); | 2094 | NOKPROBE_SYMBOL(dump_kprobe); |
| 2095 | 2095 | ||
| 2096 | int kprobe_add_ksym_blacklist(unsigned long entry) | ||
| 2097 | { | ||
| 2098 | struct kprobe_blacklist_entry *ent; | ||
| 2099 | unsigned long offset = 0, size = 0; | ||
| 2100 | |||
| 2101 | if (!kernel_text_address(entry) || | ||
| 2102 | !kallsyms_lookup_size_offset(entry, &size, &offset)) | ||
| 2103 | return -EINVAL; | ||
| 2104 | |||
| 2105 | ent = kmalloc(sizeof(*ent), GFP_KERNEL); | ||
| 2106 | if (!ent) | ||
| 2107 | return -ENOMEM; | ||
| 2108 | ent->start_addr = entry; | ||
| 2109 | ent->end_addr = entry + size; | ||
| 2110 | INIT_LIST_HEAD(&ent->list); | ||
| 2111 | list_add_tail(&ent->list, &kprobe_blacklist); | ||
| 2112 | |||
| 2113 | return (int)size; | ||
| 2114 | } | ||
| 2115 | |||
| 2116 | /* Add all symbols in given area into kprobe blacklist */ | ||
| 2117 | int kprobe_add_area_blacklist(unsigned long start, unsigned long end) | ||
| 2118 | { | ||
| 2119 | unsigned long entry; | ||
| 2120 | int ret = 0; | ||
| 2121 | |||
| 2122 | for (entry = start; entry < end; entry += ret) { | ||
| 2123 | ret = kprobe_add_ksym_blacklist(entry); | ||
| 2124 | if (ret < 0) | ||
| 2125 | return ret; | ||
| 2126 | if (ret == 0) /* In case of alias symbol */ | ||
| 2127 | ret = 1; | ||
| 2128 | } | ||
| 2129 | return 0; | ||
| 2130 | } | ||
| 2131 | |||
| 2132 | int __init __weak arch_populate_kprobe_blacklist(void) | ||
| 2133 | { | ||
| 2134 | return 0; | ||
| 2135 | } | ||
| 2136 | |||
| 2096 | /* | 2137 | /* |
| 2097 | * Lookup and populate the kprobe_blacklist. | 2138 | * Lookup and populate the kprobe_blacklist. |
| 2098 | * | 2139 | * |
| @@ -2104,26 +2145,24 @@ NOKPROBE_SYMBOL(dump_kprobe); | |||
| 2104 | static int __init populate_kprobe_blacklist(unsigned long *start, | 2145 | static int __init populate_kprobe_blacklist(unsigned long *start, |
| 2105 | unsigned long *end) | 2146 | unsigned long *end) |
| 2106 | { | 2147 | { |
| 2148 | unsigned long entry; | ||
| 2107 | unsigned long *iter; | 2149 | unsigned long *iter; |
| 2108 | struct kprobe_blacklist_entry *ent; | 2150 | int ret; |
| 2109 | unsigned long entry, offset = 0, size = 0; | ||
| 2110 | 2151 | ||
| 2111 | for (iter = start; iter < end; iter++) { | 2152 | for (iter = start; iter < end; iter++) { |
| 2112 | entry = arch_deref_entry_point((void *)*iter); | 2153 | entry = arch_deref_entry_point((void *)*iter); |
| 2113 | 2154 | ret = kprobe_add_ksym_blacklist(entry); | |
| 2114 | if (!kernel_text_address(entry) || | 2155 | if (ret == -EINVAL) |
| 2115 | !kallsyms_lookup_size_offset(entry, &size, &offset)) | ||
| 2116 | continue; | 2156 | continue; |
| 2117 | 2157 | if (ret < 0) | |
| 2118 | ent = kmalloc(sizeof(*ent), GFP_KERNEL); | 2158 | return ret; |
| 2119 | if (!ent) | ||
| 2120 | return -ENOMEM; | ||
| 2121 | ent->start_addr = entry; | ||
| 2122 | ent->end_addr = entry + size; | ||
| 2123 | INIT_LIST_HEAD(&ent->list); | ||
| 2124 | list_add_tail(&ent->list, &kprobe_blacklist); | ||
| 2125 | } | 2159 | } |
| 2126 | return 0; | 2160 | |
| 2161 | /* Symbols in __kprobes_text are blacklisted */ | ||
| 2162 | ret = kprobe_add_area_blacklist((unsigned long)__kprobes_text_start, | ||
| 2163 | (unsigned long)__kprobes_text_end); | ||
| 2164 | |||
| 2165 | return ret ? : arch_populate_kprobe_blacklist(); | ||
| 2127 | } | 2166 | } |
| 2128 | 2167 | ||
| 2129 | /* Module notifier call back, checking kprobes on the module */ | 2168 | /* Module notifier call back, checking kprobes on the module */ |
