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

Showing the changes to include/linux (3 of 11 files). Show all

Unified · Split

3 files
  1. include/linux/compiler.h +53 −0
  2. include/linux/compiler_types.h +4 −0
  3. include/linux/module.h +8 −0
include/linux/compiler.h+53−0
@@ -120,12 +120,65 @@ void ftrace_likely_update(struct ftrace_likely_data *f, int val, · 119 unmodified lines
120120 /* Annotate a C jump table to allow objtool to follow the code flow */
121121 #define __annotate_jump_table __section(.rodata..c_jump_table)
122122
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+
123171 #else
124172 #define annotate_reachable()
125173 #define annotate_unreachable()
126174 #define __annotate_jump_table
127175 #endif
128176
177+#ifndef instrumentation_begin
178+#define instrumentation_begin() do { } while(0)
179+#define instrumentation_end() do { } while(0)
180+#endif
181+
129182 #ifndef ASM_UNREACHABLE
130183 # define ASM_UNREACHABLE
131184 #endif
include/linux/compiler_types.h+4−0
@@ -118,6 +118,10 @@ struct ftrace_likely_data { · 117 unmodified lines
118118 #define notrace __attribute__((__no_instrument_function__))
119119 #endif
120120
121+/* Section for code which can't be instrumented at all */
122+#define noinstr \
123+ noinline notrace __attribute((__section__(".noinstr.text")))
124+
121125 /*
122126 * it doesn't make sense on ARM (currently the only user of __naked)
123127 * 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
458458 void __percpu *percpu;
459459 unsigned int percpu_size;
460460 #endif
461+ void *noinstr_text_start;
462+ unsigned int noinstr_text_size;
461463
462464 #ifdef CONFIG_TRACEPOINTS
463465 unsigned int num_tracepoints;
@@ -489,6 +491,12 @@ struct module { · 25 unmodified lines
489491 unsigned int num_ftrace_callsites;
490492 unsigned long *ftrace_callsites;
491493 #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
492500
493501 #ifdef CONFIG_LIVEPATCH
494502 bool klp; /* Is this a livepatch module? */