diff options
author | Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | 2018-10-13 15:10:50 -0400 |
---|---|---|
committer | Steven Rostedt (VMware) <rostedt@goodmis.org> | 2018-10-17 15:35:29 -0400 |
commit | 9c0be3f6b5d776dfe3ed249862c244a4486414dc (patch) | |
tree | 7bf3f3e4b90045293c299b0a7747adfe60e4b055 | |
parent | 62165600ae73ebd76e2d9b992b36360408d570d8 (diff) |
tracepoint: Fix tracepoint array element size mismatch
commit 46e0c9be206f ("kernel: tracepoints: add support for relative
references") changes the layout of the __tracepoint_ptrs section on
architectures supporting relative references. However, it does so
without turning struct tracepoint * const into const int elsewhere in
the tracepoint code, which has the following side-effect:
Setting mod->num_tracepoints is done in by module.c:
mod->tracepoints_ptrs = section_objs(info, "__tracepoints_ptrs",
sizeof(*mod->tracepoints_ptrs),
&mod->num_tracepoints);
Basically, since sizeof(*mod->tracepoints_ptrs) is a pointer size
(rather than sizeof(int)), num_tracepoints is erroneously set to half the
size it should be on 64-bit arch. So a module with an odd number of
tracepoints misses the last tracepoint due to effect of integer
division.
So in the module going notifier:
for_each_tracepoint_range(mod->tracepoints_ptrs,
mod->tracepoints_ptrs + mod->num_tracepoints,
tp_module_going_check_quiescent, NULL);
the expression (mod->tracepoints_ptrs + mod->num_tracepoints) actually
evaluates to something within the bounds of the array, but miss the
last tracepoint if the number of tracepoints is odd on 64-bit arch.
Fix this by introducing a new typedef: tracepoint_ptr_t, which
is either "const int" on architectures that have PREL32 relocations,
or "struct tracepoint * const" on architectures that does not have
this feature.
Also provide a new tracepoint_ptr_defer() static inline to
encapsulate deferencing this type rather than duplicate code and
ugly idefs within the for_each_tracepoint_range() implementation.
This issue appears in 4.19-rc kernels, and should ideally be fixed
before the end of the rc cycle.
Acked-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Acked-by: Jessica Yu <jeyu@kernel.org>
Link: http://lkml.kernel.org/r/20181013191050.22389-1-mathieu.desnoyers@efficios.com
Link: http://lkml.kernel.org/r/20180704083651.24360-7-ard.biesheuvel@linaro.org
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: James Morris <james.morris@microsoft.com>
Cc: James Morris <jmorris@namei.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: "Serge E. Hallyn" <serge@hallyn.com>
Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Thomas Garnier <thgarnie@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
-rw-r--r-- | include/linux/module.h | 3 | ||||
-rw-r--r-- | include/linux/tracepoint-defs.h | 6 | ||||
-rw-r--r-- | include/linux/tracepoint.h | 36 | ||||
-rw-r--r-- | kernel/tracepoint.c | 24 |
4 files changed, 39 insertions, 30 deletions
diff --git a/include/linux/module.h b/include/linux/module.h index f807f15bebbe..e19ae08c7fb8 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/export.h> | 20 | #include <linux/export.h> |
21 | #include <linux/rbtree_latch.h> | 21 | #include <linux/rbtree_latch.h> |
22 | #include <linux/error-injection.h> | 22 | #include <linux/error-injection.h> |
23 | #include <linux/tracepoint-defs.h> | ||
23 | 24 | ||
24 | #include <linux/percpu.h> | 25 | #include <linux/percpu.h> |
25 | #include <asm/module.h> | 26 | #include <asm/module.h> |
@@ -430,7 +431,7 @@ struct module { | |||
430 | 431 | ||
431 | #ifdef CONFIG_TRACEPOINTS | 432 | #ifdef CONFIG_TRACEPOINTS |
432 | unsigned int num_tracepoints; | 433 | unsigned int num_tracepoints; |
433 | struct tracepoint * const *tracepoints_ptrs; | 434 | tracepoint_ptr_t *tracepoints_ptrs; |
434 | #endif | 435 | #endif |
435 | #ifdef HAVE_JUMP_LABEL | 436 | #ifdef HAVE_JUMP_LABEL |
436 | struct jump_entry *jump_entries; | 437 | struct jump_entry *jump_entries; |
diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h index 22c5a46e9693..49ba9cde7e4b 100644 --- a/include/linux/tracepoint-defs.h +++ b/include/linux/tracepoint-defs.h | |||
@@ -35,6 +35,12 @@ struct tracepoint { | |||
35 | struct tracepoint_func __rcu *funcs; | 35 | struct tracepoint_func __rcu *funcs; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | ||
39 | typedef const int tracepoint_ptr_t; | ||
40 | #else | ||
41 | typedef struct tracepoint * const tracepoint_ptr_t; | ||
42 | #endif | ||
43 | |||
38 | struct bpf_raw_event_map { | 44 | struct bpf_raw_event_map { |
39 | struct tracepoint *tp; | 45 | struct tracepoint *tp; |
40 | void *bpf_func; | 46 | void *bpf_func; |
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 041f7e56a289..538ba1a58f5b 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -99,6 +99,29 @@ extern void syscall_unregfunc(void); | |||
99 | #define TRACE_DEFINE_ENUM(x) | 99 | #define TRACE_DEFINE_ENUM(x) |
100 | #define TRACE_DEFINE_SIZEOF(x) | 100 | #define TRACE_DEFINE_SIZEOF(x) |
101 | 101 | ||
102 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | ||
103 | static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) | ||
104 | { | ||
105 | return offset_to_ptr(p); | ||
106 | } | ||
107 | |||
108 | #define __TRACEPOINT_ENTRY(name) \ | ||
109 | asm(" .section \"__tracepoints_ptrs\", \"a\" \n" \ | ||
110 | " .balign 4 \n" \ | ||
111 | " .long __tracepoint_" #name " - . \n" \ | ||
112 | " .previous \n") | ||
113 | #else | ||
114 | static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) | ||
115 | { | ||
116 | return *p; | ||
117 | } | ||
118 | |||
119 | #define __TRACEPOINT_ENTRY(name) \ | ||
120 | static tracepoint_ptr_t __tracepoint_ptr_##name __used \ | ||
121 | __attribute__((section("__tracepoints_ptrs"))) = \ | ||
122 | &__tracepoint_##name | ||
123 | #endif | ||
124 | |||
102 | #endif /* _LINUX_TRACEPOINT_H */ | 125 | #endif /* _LINUX_TRACEPOINT_H */ |
103 | 126 | ||
104 | /* | 127 | /* |
@@ -253,19 +276,6 @@ extern void syscall_unregfunc(void); | |||
253 | return static_key_false(&__tracepoint_##name.key); \ | 276 | return static_key_false(&__tracepoint_##name.key); \ |
254 | } | 277 | } |
255 | 278 | ||
256 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | ||
257 | #define __TRACEPOINT_ENTRY(name) \ | ||
258 | asm(" .section \"__tracepoints_ptrs\", \"a\" \n" \ | ||
259 | " .balign 4 \n" \ | ||
260 | " .long __tracepoint_" #name " - . \n" \ | ||
261 | " .previous \n") | ||
262 | #else | ||
263 | #define __TRACEPOINT_ENTRY(name) \ | ||
264 | static struct tracepoint * const __tracepoint_ptr_##name __used \ | ||
265 | __attribute__((section("__tracepoints_ptrs"))) = \ | ||
266 | &__tracepoint_##name | ||
267 | #endif | ||
268 | |||
269 | /* | 279 | /* |
270 | * We have no guarantee that gcc and the linker won't up-align the tracepoint | 280 | * We have no guarantee that gcc and the linker won't up-align the tracepoint |
271 | * structures, so we create an array of pointers that will be used for iteration | 281 | * structures, so we create an array of pointers that will be used for iteration |
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index bf2c06ef9afc..a3be42304485 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c | |||
@@ -28,8 +28,8 @@ | |||
28 | #include <linux/sched/task.h> | 28 | #include <linux/sched/task.h> |
29 | #include <linux/static_key.h> | 29 | #include <linux/static_key.h> |
30 | 30 | ||
31 | extern struct tracepoint * const __start___tracepoints_ptrs[]; | 31 | extern tracepoint_ptr_t __start___tracepoints_ptrs[]; |
32 | extern struct tracepoint * const __stop___tracepoints_ptrs[]; | 32 | extern tracepoint_ptr_t __stop___tracepoints_ptrs[]; |
33 | 33 | ||
34 | DEFINE_SRCU(tracepoint_srcu); | 34 | DEFINE_SRCU(tracepoint_srcu); |
35 | EXPORT_SYMBOL_GPL(tracepoint_srcu); | 35 | EXPORT_SYMBOL_GPL(tracepoint_srcu); |
@@ -371,25 +371,17 @@ int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data) | |||
371 | } | 371 | } |
372 | EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); | 372 | EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); |
373 | 373 | ||
374 | static void for_each_tracepoint_range(struct tracepoint * const *begin, | 374 | static void for_each_tracepoint_range( |
375 | struct tracepoint * const *end, | 375 | tracepoint_ptr_t *begin, tracepoint_ptr_t *end, |
376 | void (*fct)(struct tracepoint *tp, void *priv), | 376 | void (*fct)(struct tracepoint *tp, void *priv), |
377 | void *priv) | 377 | void *priv) |
378 | { | 378 | { |
379 | tracepoint_ptr_t *iter; | ||
380 | |||
379 | if (!begin) | 381 | if (!begin) |
380 | return; | 382 | return; |
381 | 383 | for (iter = begin; iter < end; iter++) | |
382 | if (IS_ENABLED(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)) { | 384 | fct(tracepoint_ptr_deref(iter), priv); |
383 | const int *iter; | ||
384 | |||
385 | for (iter = (const int *)begin; iter < (const int *)end; iter++) | ||
386 | fct(offset_to_ptr(iter), priv); | ||
387 | } else { | ||
388 | struct tracepoint * const *iter; | ||
389 | |||
390 | for (iter = begin; iter < end; iter++) | ||
391 | fct(*iter, priv); | ||
392 | } | ||
393 | } | 385 | } |
394 | 386 | ||
395 | #ifdef CONFIG_MODULES | 387 | #ifdef CONFIG_MODULES |