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 | /* 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 | #else | 171 | #else |
| 124 | #define annotate_reachable() | 172 | #define annotate_reachable() |
| 125 | #define annotate_unreachable() | 173 | #define annotate_unreachable() |
| 126 | #define __annotate_jump_table | 174 | #define __annotate_jump_table |
| 127 | #endif | 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 | #ifndef ASM_UNREACHABLE | 182 | #ifndef ASM_UNREACHABLE |
| 130 | # define ASM_UNREACHABLE | 183 | # define ASM_UNREACHABLE |
| 131 | #endif | 184 | #endif |
| @@ -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 | #endif | 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 | * 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 without | 127 | * to trace naked functions because then mcount is called without |
| @@ -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 | #endif | 460 | #endif |
| 461 | void *noinstr_text_start; | ||
| 462 | unsigned int noinstr_text_size; | ||
| 461 | 463 | ||
| 462 | #ifdef CONFIG_TRACEPOINTS | 464 | #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 | #endif | 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 | #ifdef CONFIG_LIVEPATCH | 501 | #ifdef CONFIG_LIVEPATCH |
| 494 | bool klp; /* Is this a livepatch module? */ | 502 | bool klp; /* Is this a livepatch module? */ |