aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathieu Desnoyers <mathieu.desnoyers@efficios.com>2018-10-13 15:10:50 -0400
committerSteven Rostedt (VMware) <rostedt@goodmis.org>2018-10-17 15:35:29 -0400
commit9c0be3f6b5d776dfe3ed249862c244a4486414dc (patch)
tree7bf3f3e4b90045293c299b0a7747adfe60e4b055
parent62165600ae73ebd76e2d9b992b36360408d570d8 (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.h3
-rw-r--r--include/linux/tracepoint-defs.h6
-rw-r--r--include/linux/tracepoint.h36
-rw-r--r--kernel/tracepoint.c24
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
39typedef const int tracepoint_ptr_t;
40#else
41typedef struct tracepoint * const tracepoint_ptr_t;
42#endif
43
38struct bpf_raw_event_map { 44struct 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
103static 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
114static 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
31extern struct tracepoint * const __start___tracepoints_ptrs[]; 31extern tracepoint_ptr_t __start___tracepoints_ptrs[];
32extern struct tracepoint * const __stop___tracepoints_ptrs[]; 32extern tracepoint_ptr_t __stop___tracepoints_ptrs[];
33 33
34DEFINE_SRCU(tracepoint_srcu); 34DEFINE_SRCU(tracepoint_srcu);
35EXPORT_SYMBOL_GPL(tracepoint_srcu); 35EXPORT_SYMBOL_GPL(tracepoint_srcu);
@@ -371,25 +371,17 @@ int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data)
371} 371}
372EXPORT_SYMBOL_GPL(tracepoint_probe_unregister); 372EXPORT_SYMBOL_GPL(tracepoint_probe_unregister);
373 373
374static void for_each_tracepoint_range(struct tracepoint * const *begin, 374static 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