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
Showing the changes to include/linux (3 of 11 files). Show all
Unified · Split
| @@ -120,12 +120,65 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, · 119 unmodified lines | ||
| 120 | 120 | /* Annotate a C jump table to allow objtool to follow the code flow */ |
| 121 | 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 | 171 | #else |
| 124 | 172 | #define annotate_reachable() |
| 125 | 173 | #define annotate_unreachable() |
| 126 | 174 | #define __annotate_jump_table |
| 127 | 175 | #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 | 182 | #ifndef ASM_UNREACHABLE |
| 130 | 183 | # define ASM_UNREACHABLE |
| 131 | 184 | #endif |
| @@ -118,6 +118,10 @@ struct ftrace_likely_data { · 117 unmodified lines | ||
| 118 | 118 | #define notrace __attribute__((__no_instrument_function__)) |
| 119 | 119 | #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 | 126 | * it doesn't make sense on ARM (currently the only user of __naked) |
| 123 | 127 | * to trace naked functions because then mcount is called without |
| @@ -458,6 +458,8 @@ struct module { · 457 unmodified lines | ||
| 458 | 458 | void __percpu *percpu; |
| 459 | 459 | unsigned int percpu_size; |
| 460 | 460 | #endif |
| 461 | + void *noinstr_text_start; | |
| 462 | + unsigned int noinstr_text_size; | |
| 461 | 463 | |
| 462 | 464 | #ifdef CONFIG_TRACEPOINTS |
| 463 | 465 | unsigned int num_tracepoints; |
| @@ -489,6 +491,12 @@ struct module { · 25 unmodified lines | ||
| 489 | 491 | unsigned int num_ftrace_callsites; |
| 490 | 492 | unsigned long *ftrace_callsites; |
| 491 | 493 | #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 | 501 | #ifdef CONFIG_LIVEPATCH |
| 494 | 502 | bool klp; /* Is this a livepatch module? */ |