History

Merge tag 'core-kprobes-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull kprobes updates from Ingo Molnar: "Various kprobes updates, mostly centered around cleaning up the no-instrumentation logic. Instead of the current per debug facility blacklist, use the more generic .noinstr.text approach, combined with a 'noinstr' marker for functions. Also add instrumentation_begin()/end() to better manage the exact place in entry code where instrumentation may be used. And add a kprobes blacklist for modules" * tag 'core-kprobes-2020-06-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: kprobes: Prevent probes in .noinstr.text section vmlinux.lds.h: Create section for protection against instrumentation samples/kprobes: Add __kprobes and NOKPROBE_SYMBOL() for handlers. kprobes: Support NOKPROBE_SYMBOL() in modules kprobes: Support __kprobes blacklist in modules kprobes: Lock kprobe_mutex while showing kprobe_blacklist

Linus Torvalds committed 6 years ago

Commit 0bd957e2 parents 9bf9511 66e9b0711 files · +180 −4Browse files

Unified · Split

11 files
  1. arch/powerpc/kernel/vmlinux.lds.S +1 −0
  2. include/asm-generic/sections.h +3 −0
  3. include/asm-generic/vmlinux.lds.h +10 −0
  4. include/linux/compiler.h +53 −0
  5. include/linux/compiler_types.h +4 −0
  6. include/linux/module.h +8 −0
  7. kernel/kprobes.c +84 −1
  8. kernel/module.c +10 −0
  9. samples/kprobes/kprobe_example.c +4 −2
  10. samples/kprobes/kretprobe_example.c +2 −0
  11. scripts/mod/modpost.c +1 −1
arch/powerpc/kernel/vmlinux.lds.S+1−0
@@ -90,6 +90,7 @@ SECTIONS · 89 unmodified lines
90#ifdef CONFIG_PPC6490#ifdef CONFIG_PPC64
91 *(.tramp.ftrace.text);91 *(.tramp.ftrace.text);
92#endif92#endif
93 NOINSTR_TEXT
93 SCHED_TEXT94 SCHED_TEXT
94 CPUIDLE_TEXT95 CPUIDLE_TEXT
95 LOCK_TEXT96 LOCK_TEXT
include/asm-generic/sections.h+3−0
@@ -53,6 +53,9 @@ extern char __ctors_start[], __ctors_end[]; · 52 unmodified lines
53/* Start and end of .opd section - used for function descriptors. */53/* Start and end of .opd section - used for function descriptors. */
54extern char __start_opd[], __end_opd[];54extern char __start_opd[], __end_opd[];
55 55
56/* Start and end of instrumentation protected text section */
57extern char __noinstr_text_start[], __noinstr_text_end[];
58
56extern __visible const void __nosave_begin, __nosave_end;59extern __visible const void __nosave_begin, __nosave_end;
57 60
58/* Function descriptor handling (if any). Override in asm/sections.h */61/* Function descriptor handling (if any). Override in asm/sections.h */
include/asm-generic/vmlinux.lds.h+10−0
@@ -540,6 +540,15 @@ · 539 unmodified lines
540 . = ALIGN((align)); \540 . = ALIGN((align)); \
541 __end_rodata = .;541 __end_rodata = .;
542 542
543/*
544 * Non-instrumentable text section
545 */
546#define NOINSTR_TEXT \
547 ALIGN_FUNCTION(); \
548 __noinstr_text_start = .; \
549 *(.noinstr.text) \
550 __noinstr_text_end = .;
551
543/*552/*
544 * .text section. Map to function alignment to avoid address changes553 * .text section. Map to function alignment to avoid address changes
545 * during second ld run in second ld pass when generating System.map554 * during second ld run in second ld pass when generating System.map
@@ -551,6 +560,7 @@ · 5 unmodified lines
551#define TEXT_TEXT \560#define TEXT_TEXT \
552 ALIGN_FUNCTION(); \561 ALIGN_FUNCTION(); \
553 *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \562 *(.text.hot TEXT_MAIN .text.fixup .text.unlikely) \
563 NOINSTR_TEXT \
554 *(.text..refcount) \564 *(.text..refcount) \
555 *(.ref.text) \565 *(.ref.text) \
556 MEM_KEEP(init.text*) \566 MEM_KEEP(init.text*) \
include/linux/compiler.h+53−0
@@ -120,12 +120,65 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, · 119 unmodified lines
120/* Annotate a C jump table to allow objtool to follow the code flow */120/* Annotate a C jump table to allow objtool to follow the code flow */
121#define __annotate_jump_table __section(.rodata..c_jump_table)121#define __annotate_jump_table __section(.rodata..c_jump_table)
122 122
123#ifdef CONFIG_DEBUG_ENTRY
124/* Begin/end of an instrumentation safe region */
125#define instrumentation_begin() ({ \
126 asm volatile("%c0:\n\t" \
127 ".pushsection .discard.instr_begin\n\t" \
128 ".long %c0b - .\n\t" \
129 ".popsection\n\t" : : "i" (__COUNTER__)); \
130})
131
132/*
133 * Because instrumentation_{begin,end}() can nest, objtool validation considers
134 * _begin() a +1 and _end() a -1 and computes a sum over the instructions.
135 * When the value is greater than 0, we consider instrumentation allowed.
136 *
137 * There is a problem with code like:
138 *
139 * noinstr void foo()
140 * {
141 * instrumentation_begin();
142 * ...
143 * if (cond) {
144 * instrumentation_begin();
145 * ...
146 * instrumentation_end();
147 * }
148 * bar();
149 * instrumentation_end();
150 * }
151 *
152 * If instrumentation_end() would be an empty label, like all the other
153 * annotations, the inner _end(), which is at the end of a conditional block,
154 * would land on the instruction after the block.
155 *
156 * If we then consider the sum of the !cond path, we'll see that the call to
157 * bar() is with a 0-value, even though, we meant it to happen with a positive
158 * value.
159 *
160 * To avoid this, have _end() be a NOP instruction, this ensures it will be
161 * part of the condition block and does not escape.
162 */
163#define instrumentation_end() ({ \
164 asm volatile("%c0: nop\n\t" \
165 ".pushsection .discard.instr_end\n\t" \
166 ".long %c0b - .\n\t" \
167 ".popsection\n\t" : : "i" (__COUNTER__)); \
168})
169#endif /* CONFIG_DEBUG_ENTRY */
170
123#else171#else
124#define annotate_reachable()172#define annotate_reachable()
125#define annotate_unreachable()173#define annotate_unreachable()
126#define __annotate_jump_table174#define __annotate_jump_table
127#endif175#endif
128 176
177#ifndef instrumentation_begin
178#define instrumentation_begin() do { } while(0)
179#define instrumentation_end() do { } while(0)
180#endif
181
129#ifndef ASM_UNREACHABLE182#ifndef ASM_UNREACHABLE
130# define ASM_UNREACHABLE183# define ASM_UNREACHABLE
131#endif184#endif
include/linux/compiler_types.h+4−0
@@ -118,6 +118,10 @@ struct ftrace_likely_data { · 117 unmodified lines
118#define notrace __attribute__((__no_instrument_function__))118#define notrace __attribute__((__no_instrument_function__))
119#endif119#endif
120 120
121/* Section for code which can't be instrumented at all */
122#define noinstr \
123 noinline notrace __attribute((__section__(".noinstr.text")))
124
121/*125/*
122 * it doesn't make sense on ARM (currently the only user of __naked)126 * it doesn't make sense on ARM (currently the only user of __naked)
123 * to trace naked functions because then mcount is called without127 * to trace naked functions because then mcount is called without
include/linux/module.h+8−0
@@ -458,6 +458,8 @@ struct module { · 457 unmodified lines
458 void __percpu *percpu;458 void __percpu *percpu;
459 unsigned int percpu_size;459 unsigned int percpu_size;
460#endif460#endif
461 void *noinstr_text_start;
462 unsigned int noinstr_text_size;
461 463
462#ifdef CONFIG_TRACEPOINTS464#ifdef CONFIG_TRACEPOINTS
463 unsigned int num_tracepoints;465 unsigned int num_tracepoints;
@@ -489,6 +491,12 @@ struct module { · 25 unmodified lines
489 unsigned int num_ftrace_callsites;491 unsigned int num_ftrace_callsites;
490 unsigned long *ftrace_callsites;492 unsigned long *ftrace_callsites;
491#endif493#endif
494#ifdef CONFIG_KPROBES
495 void *kprobes_text_start;
496 unsigned int kprobes_text_size;
497 unsigned long *kprobe_blacklist;
498 unsigned int num_kprobe_blacklist;
499#endif
492 500
493#ifdef CONFIG_LIVEPATCH501#ifdef CONFIG_LIVEPATCH
494 bool klp; /* Is this a livepatch module? */502 bool klp; /* Is this a livepatch module? */
kernel/kprobes.c+84−1
@@ -2179,6 +2179,24 @@ int kprobe_add_area_blacklist(unsigned long start, unsigned long end) · 2178 unmodified lines
2179 return 0;2179 return 0;
2180}2180}
2181 2181
2182/* Remove all symbols in given area from kprobe blacklist */
2183static void kprobe_remove_area_blacklist(unsigned long start, unsigned long end)
2184{
2185 struct kprobe_blacklist_entry *ent, *n;
2186
2187 list_for_each_entry_safe(ent, n, &kprobe_blacklist, list) {
2188 if (ent->start_addr < start || ent->start_addr >= end)
2189 continue;
2190 list_del(&ent->list);
2191 kfree(ent);
2192 }
2193}
2194
2195static void kprobe_remove_ksym_blacklist(unsigned long entry)
2196{
2197 kprobe_remove_area_blacklist(entry, entry + 1);
2198}
2199
2182int __init __weak arch_populate_kprobe_blacklist(void)2200int __init __weak arch_populate_kprobe_blacklist(void)
2183{2201{
2184 return 0;2202 return 0;
@@ -2211,10 +2229,62 @@ static int __init populate_kprobe_blacklist(unsigned long *start, · 26 unmodified lines
2211 /* Symbols in __kprobes_text are blacklisted */2229 /* Symbols in __kprobes_text are blacklisted */
2212 ret = kprobe_add_area_blacklist((unsigned long)__kprobes_text_start,2230 ret = kprobe_add_area_blacklist((unsigned long)__kprobes_text_start,
2213 (unsigned long)__kprobes_text_end);2231 (unsigned long)__kprobes_text_end);
2232 if (ret)
2233 return ret;
2234
2235 /* Symbols in noinstr section are blacklisted */
2236 ret = kprobe_add_area_blacklist((unsigned long)__noinstr_text_start,
2237 (unsigned long)__noinstr_text_end);
2214 2238
2215 return ret ? : arch_populate_kprobe_blacklist();2239 return ret ? : arch_populate_kprobe_blacklist();
2216}2240}
2217 2241
2242static void add_module_kprobe_blacklist(struct module *mod)
2243{
2244 unsigned long start, end;
2245 int i;
2246
2247 if (mod->kprobe_blacklist) {
2248 for (i = 0; i < mod->num_kprobe_blacklist; i++)
2249 kprobe_add_ksym_blacklist(mod->kprobe_blacklist[i]);
2250 }
2251
2252 start = (unsigned long)mod->kprobes_text_start;
2253 if (start) {
2254 end = start + mod->kprobes_text_size;
2255 kprobe_add_area_blacklist(start, end);
2256 }
2257
2258 start = (unsigned long)mod->noinstr_text_start;
2259 if (start) {
2260 end = start + mod->noinstr_text_size;
2261 kprobe_add_area_blacklist(start, end);
2262 }
2263}
2264
2265static void remove_module_kprobe_blacklist(struct module *mod)
2266{
2267 unsigned long start, end;
2268 int i;
2269
2270 if (mod->kprobe_blacklist) {
2271 for (i = 0; i < mod->num_kprobe_blacklist; i++)
2272 kprobe_remove_ksym_blacklist(mod->kprobe_blacklist[i]);
2273 }
2274
2275 start = (unsigned long)mod->kprobes_text_start;
2276 if (start) {
2277 end = start + mod->kprobes_text_size;
2278 kprobe_remove_area_blacklist(start, end);
2279 }
2280
2281 start = (unsigned long)mod->noinstr_text_start;
2282 if (start) {
2283 end = start + mod->noinstr_text_size;
2284 kprobe_remove_area_blacklist(start, end);
2285 }
2286}
2287
2218/* Module notifier call back, checking kprobes on the module */2288/* Module notifier call back, checking kprobes on the module */
2219static int kprobes_module_callback(struct notifier_block *nb,2289static int kprobes_module_callback(struct notifier_block *nb,
2220 unsigned long val, void *data)2290 unsigned long val, void *data)
@@ -2225,6 +2295,11 @@ static int kprobes_module_callback(struct notifier_block *nb, · 4 unmodified lines
2225 unsigned int i;2295 unsigned int i;
2226 int checkcore = (val == MODULE_STATE_GOING);2296 int checkcore = (val == MODULE_STATE_GOING);
2227 2297
2298 if (val == MODULE_STATE_COMING) {
2299 mutex_lock(&kprobe_mutex);
2300 add_module_kprobe_blacklist(mod);
2301 mutex_unlock(&kprobe_mutex);
2302 }
2228 if (val != MODULE_STATE_GOING && val != MODULE_STATE_LIVE)2303 if (val != MODULE_STATE_GOING && val != MODULE_STATE_LIVE)
2229 return NOTIFY_DONE;2304 return NOTIFY_DONE;
2230 2305
@@ -2255,6 +2330,8 @@ static int kprobes_module_callback(struct notifier_block *nb, · 24 unmodified lines
2255 kill_kprobe(p);2330 kill_kprobe(p);
2256 }2331 }
2257 }2332 }
2333 if (val == MODULE_STATE_GOING)
2334 remove_module_kprobe_blacklist(mod);
2258 mutex_unlock(&kprobe_mutex);2335 mutex_unlock(&kprobe_mutex);
2259 return NOTIFY_DONE;2336 return NOTIFY_DONE;
2260}2337}
@@ -2420,6 +2497,7 @@ static const struct file_operations debugfs_kprobes_operations = { · 159 unmodified lines
2420/* kprobes/blacklist -- shows which functions can not be probed */2497/* kprobes/blacklist -- shows which functions can not be probed */
2421static void *kprobe_blacklist_seq_start(struct seq_file *m, loff_t *pos)2498static void *kprobe_blacklist_seq_start(struct seq_file *m, loff_t *pos)
2422{2499{
2500 mutex_lock(&kprobe_mutex);
2423 return seq_list_start(&kprobe_blacklist, *pos);2501 return seq_list_start(&kprobe_blacklist, *pos);
2424}2502}
2425 2503
@@ -2446,10 +2524,15 @@ static int kprobe_blacklist_seq_show(struct seq_file *m, void *v) · 20 unmodified lines
2446 return 0;2524 return 0;
2447}2525}
2448 2526
2527static void kprobe_blacklist_seq_stop(struct seq_file *f, void *v)
2528{
2529 mutex_unlock(&kprobe_mutex);
2530}
2531
2449static const struct seq_operations kprobe_blacklist_seq_ops = {2532static const struct seq_operations kprobe_blacklist_seq_ops = {
2450 .start = kprobe_blacklist_seq_start,2533 .start = kprobe_blacklist_seq_start,
2451 .next = kprobe_blacklist_seq_next,2534 .next = kprobe_blacklist_seq_next,
2452 .stop = kprobe_seq_stop, /* Reuse void function */2535 .stop = kprobe_blacklist_seq_stop,
2453 .show = kprobe_blacklist_seq_show,2536 .show = kprobe_blacklist_seq_show,
2454};2537};
2455 2538
kernel/module.c+10−0
@@ -3150,6 +3150,9 @@ static int find_module_sections(struct module *mod, struct load_info *info) · 3149 unmodified lines
3150 }3150 }
3151#endif3151#endif
3152 3152
3153 mod->noinstr_text_start = section_objs(info, ".noinstr.text", 1,
3154 &mod->noinstr_text_size);
3155
3153#ifdef CONFIG_TRACEPOINTS3156#ifdef CONFIG_TRACEPOINTS
3154 mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs",3157 mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs",
3155 sizeof(*mod->tracepoints_ptrs),3158 sizeof(*mod->tracepoints_ptrs),
@@ -3193,6 +3196,13 @@ static int find_module_sections(struct module *mod, struct load_info *info) · 37 unmodified lines
3193 mod->ei_funcs = section_objs(info, "_error_injection_whitelist",3196 mod->ei_funcs = section_objs(info, "_error_injection_whitelist",
3194 sizeof(*mod->ei_funcs),3197 sizeof(*mod->ei_funcs),
3195 &mod->num_ei_funcs);3198 &mod->num_ei_funcs);
3199#endif
3200#ifdef CONFIG_KPROBES
3201 mod->kprobes_text_start = section_objs(info, ".kprobes.text", 1,
3202 &mod->kprobes_text_size);
3203 mod->kprobe_blacklist = section_objs(info, "_kprobe_blacklist",
3204 sizeof(unsigned long),
3205 &mod->num_kprobe_blacklist);
3196#endif3206#endif
3197 mod->extable = section_objs(info, "__ex_table",3207 mod->extable = section_objs(info, "__ex_table",
3198 sizeof(*mod->extable), &mod->num_exentries);3208 sizeof(*mod->extable), &mod->num_exentries);
samples/kprobes/kprobe_example.c+4−2
@@ -25,7 +25,7 @@ static struct kprobe kp = { · 24 unmodified lines
25};25};
26 26
27/* kprobe pre_handler: called just before the probed instruction is executed */27/* kprobe pre_handler: called just before the probed instruction is executed */
28static int handler_pre(struct kprobe *p, struct pt_regs *regs)28static int __kprobes handler_pre(struct kprobe *p, struct pt_regs *regs)
29{29{
30#ifdef CONFIG_X8630#ifdef CONFIG_X86
31 pr_info("<%s> pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",31 pr_info("<%s> pre_handler: p->addr = 0x%p, ip = %lx, flags = 0x%lx\n",
@@ -54,7 +54,7 @@ static int handler_pre(struct kprobe *p, struct pt_regs *regs) · 22 unmodified lines
54}54}
55 55
56/* kprobe post_handler: called after the probed instruction is executed */56/* kprobe post_handler: called after the probed instruction is executed */
57static void handler_post(struct kprobe *p, struct pt_regs *regs,57static void __kprobes handler_post(struct kprobe *p, struct pt_regs *regs,
58 unsigned long flags)58 unsigned long flags)
59{59{
60#ifdef CONFIG_X8660#ifdef CONFIG_X86
@@ -90,6 +90,8 @@ static int handler_fault(struct kprobe *p, struct pt_regs *regs, int trapnr) · 29 unmodified lines
90 /* Return 0 because we don't handle the fault. */90 /* Return 0 because we don't handle the fault. */
91 return 0;91 return 0;
92}92}
93/* NOKPROBE_SYMBOL() is also available */
94NOKPROBE_SYMBOL(handler_fault);
93 95
94static int __init kprobe_init(void)96static int __init kprobe_init(void)
95{97{
samples/kprobes/kretprobe_example.c+2−0
@@ -48,6 +48,7 @@ static int entry_handler(struct kretprobe_instance *ri, struct pt_regs *regs) · 47 unmodified lines
48 data->entry_stamp = ktime_get();48 data->entry_stamp = ktime_get();
49 return 0;49 return 0;
50}50}
51NOKPROBE_SYMBOL(entry_handler);
51 52
52/*53/*
53 * Return-probe handler: Log the return value and duration. Duration may turn54 * Return-probe handler: Log the return value and duration. Duration may turn
@@ -67,6 +68,7 @@ static int ret_handler(struct kretprobe_instance *ri, struct pt_regs *regs) · 13 unmodified lines
67 func_name, retval, (long long)delta);68 func_name, retval, (long long)delta);
68 return 0;69 return 0;
69}70}
71NOKPROBE_SYMBOL(ret_handler);
70 72
71static struct kretprobe my_kretprobe = {73static struct kretprobe my_kretprobe = {
72 .handler = ret_handler,74 .handler = ret_handler,
scripts/mod/modpost.c+1−1
@@ -948,7 +948,7 @@ static void check_section(const char *modname, struct elf_info *elf, · 947 unmodified lines
948 948
949#define DATA_SECTIONS ".data", ".data.rel"949#define DATA_SECTIONS ".data", ".data.rel"
950#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \950#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \
951 ".kprobes.text", ".cpuidle.text"951 ".kprobes.text", ".cpuidle.text", ".noinstr.text"
952#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \952#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \
953 ".fixup", ".entry.text", ".exception.text", ".text.*", \953 ".fixup", ".entry.text", ".exception.text", ".text.*", \
954 ".coldtext"954 ".coldtext"

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t