From: Mathieu Desnoyers <[email protected]>
Commit 1d562f197d01a ("ms/objtool: Exclude __tracepoints data from
ENDBR checks") was backported from mainstream, which excludes the
__tracepoints section from objtool's IBT validation. This causes
regfunc/unregfunc function pointers stored directly in struct tracepoint
to have their ENDBR instructions incorrectly sealed at boot, resulting
in a kernel crash when called indirectly with CONFIG_X86_KERNEL_IBT=y.
In mainstream, this commit amends the crash by moving regfunc/unregfunc
into a separate struct tracepoint_ext outside the __tracepoints section,
and should be backported alongside it.
Tested-by: Jordan Rife <[email protected]>
Cc: Michael Jeanson <[email protected]>
Cc: Thomas Gleixner <[email protected]>
Cc: Masami Hiramatsu <[email protected]>
Cc: Peter Zijlstra <[email protected]>
Cc: Alexei Starovoitov <[email protected]>
Cc: Yonghong Song <[email protected]>
Cc: Paul E. McKenney <[email protected]>
Cc: Ingo Molnar <[email protected]>
Cc: Arnaldo Carvalho de Melo <[email protected]>
Cc: Mark Rutland <[email protected]>
Cc: Alexander Shishkin <[email protected]>
Cc: Namhyung Kim <[email protected]>
Cc: Andrii Nakryiko <[email protected]>
Cc: [email protected]
Cc: Joel Fernandes <[email protected]>
Cc: Jordan Rife <[email protected]>
Cc: [email protected]
Link:
https://lore.kernel.org/[email protected]
Signed-off-by: Mathieu Desnoyers <[email protected]>
Signed-off-by: Steven Rostedt (Google) <[email protected]>
(cherry picked from commit a9cfb8778c43fc473ae16cddb6e9611705721b31)
Signed-off-by: Eva Kurchatova <[email protected]>
https://virtuozzo.atlassian.net/browse/VSTOR-131560
Feature: fix tracepoint
---
include/linux/tracepoint-defs.h | 8 ++++++--
include/linux/tracepoint.h | 19 +++++++++++++------
kernel/tracepoint.c | 8 ++++----
3 files changed, 23 insertions(+), 12 deletions(-)
diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h
index 4dc4955f0fbf..e1af02e375d6 100644
--- a/include/linux/tracepoint-defs.h
+++ b/include/linux/tracepoint-defs.h
@@ -29,6 +29,11 @@ struct tracepoint_func {
int prio;
};
+struct tracepoint_ext {
+ int (*regfunc)(void);
+ void (*unregfunc)(void);
+};
+
struct tracepoint {
const char *name; /* Tracepoint name */
struct static_key key;
@@ -36,9 +41,8 @@ struct tracepoint {
void *static_call_tramp;
void *iterator;
void *probestub;
- int (*regfunc)(void);
- void (*unregfunc)(void);
struct tracepoint_func __rcu *funcs;
+ struct tracepoint_ext *ext;
};
#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 93a9f3070b48..583d962abcc3 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -319,7 +319,7 @@ static inline struct tracepoint
*tracepoint_ptr_deref(tracepoint_ptr_t *p)
* structures, so we create an array of pointers that will be used for
iteration
* on the tracepoints.
*/
-#define DEFINE_TRACE_FN(_name, _reg, _unreg, proto, args) \
+#define __DEFINE_TRACE_EXT(_name, _ext, proto, args) \
static const char __tpstrtab_##_name[] \
__section("__tracepoints_strings") = #_name; \
extern struct static_call_key STATIC_CALL_KEY(tp_func_##_name); \
@@ -333,9 +333,9 @@ static inline struct tracepoint
*tracepoint_ptr_deref(tracepoint_ptr_t *p)
.static_call_tramp = STATIC_CALL_TRAMP_ADDR(tp_func_##_name), \
.iterator = &__traceiter_##_name, \
.probestub = &__probestub_##_name, \
- .regfunc = _reg, \
- .unregfunc = _unreg, \
- .funcs = NULL }; \
+ .funcs = NULL, \
+ .ext = _ext, \
+ }; \
__TRACEPOINT_ENTRY(_name); \
int __traceiter_##_name(void *__data, proto) \
{ \
@@ -358,8 +358,15 @@ static inline struct tracepoint
*tracepoint_ptr_deref(tracepoint_ptr_t *p)
} \
DEFINE_STATIC_CALL(tp_func_##_name, __traceiter_##_name);
-#define DEFINE_TRACE(name, proto, args) \
- DEFINE_TRACE_FN(name, NULL, NULL, PARAMS(proto), PARAMS(args));
+#define DEFINE_TRACE_FN(_name, _reg, _unreg, _proto, _args) \
+ static struct tracepoint_ext __tracepoint_ext_##_name = { \
+ .regfunc = _reg, \
+ .unregfunc = _unreg, \
+ }; \
+ __DEFINE_TRACE_EXT(_name, &__tracepoint_ext_##_name, PARAMS(_proto),
PARAMS(_args));
+
+#define DEFINE_TRACE(_name, _proto, _args) \
+ __DEFINE_TRACE_EXT(_name, NULL, PARAMS(_proto), PARAMS(_args));
#define EXPORT_TRACEPOINT_SYMBOL_GPL(name) \
EXPORT_SYMBOL_GPL(__tracepoint_##name); \
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index 8879da16ef4d..ebab4290d486 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -327,8 +327,8 @@ static int tracepoint_add_func(struct tracepoint *tp,
struct tracepoint_func *old, *tp_funcs;
int ret;
- if (tp->regfunc && !static_key_enabled(&tp->key)) {
- ret = tp->regfunc();
+ if (tp->ext && tp->ext->regfunc && !static_key_enabled(&tp->key)) {
+ ret = tp->ext->regfunc();
if (ret < 0)
return ret;
}
@@ -411,8 +411,8 @@ static int tracepoint_remove_func(struct tracepoint *tp,
switch (nr_func_state(tp_funcs)) {
case TP_FUNC_0: /* 1->0 */
/* Removed last function */
- if (tp->unregfunc && static_key_enabled(&tp->key))
- tp->unregfunc();
+ if (tp->ext && tp->ext->unregfunc &&
static_key_enabled(&tp->key))
+ tp->ext->unregfunc();
static_key_disable(&tp->key);
/* Set iterator static call */