FAILED: patch "[PATCH] tracing: Take the reference before publishing the named" failed to apply to 6.6-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 0fe23b8eaba0d3372c66b7b31204408da0715edc
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026091639-aim-spindle-49e1@gregkh' --subject-prefix 'PATCH 6.6.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 0fe23b8eaba0d3372c66b7b31204408da0715edc Mon Sep 17 00:00:00 2001
From: Donggeun Yoo <[email protected]>
Date: Mon, 7 Sep 2026 21:44:19 +0900
Subject: [PATCH] tracing: Take the reference before publishing the named
histogram trigger
event_hist_trigger_named_init() puts the trigger on the global named_triggers list and only then takes the reference on the trigger it shares its histogram with:
data->ref++;
save_named_trigger(data->named_data->name, data);
ret = event_hist_trigger_init(data->named_data);
if (ret < 0) {
kfree(data->cmd_ops);
data->cmd_ops = &trigger_hist_cmd;
}
return ret;event_hist_trigger_init() fails when alloc_hist_pad() cannot allocate, and nothing takes the trigger back off the list on the way out. event_hist_trigger_parse() frees it, and the next lookup by name reads the freed object:
BUG: KASAN: slab-use-after-free in find_named_trigger+0xac/0xc0 Read of size 8 at addr ffff888009346860 by task init/1 find_named_trigger+0xac/0xc0 hist_register_trigger+0xc1/0xa00 event_hist_trigger_parse+0x3146/0x6af0 event_trigger_write+0xce/0x160 Freed by task 67: kfree+0x154/0x420 trigger_kthread_fn+0xfd/0x160
Do the reference first and publish once it has succeeded, so that nothing which can fail runs after the trigger becomes findable.
kernel/trace/trace_events_hist.c +6 -5
@@ -6371,17 +6371,18 @@ static int event_hist_trigger_named_init(struct event_trigger_data *data) {int ret; - data->ref++; - -save_named_trigger (data->named_data->name, data); - ret =event_hist_trigger_init (data->named_data);if (ret <0 ) {kfree (data->cmd_ops); data->cmd_ops = &trigger_hist_cmd; +return ret; } -return ret; + data->ref++; + +save_named_trigger (data->named_data->name, data); + +return 0 ; }static void event_hist_trigger_named_free (struct event_trigger_data *data)
Sasha Levin
maintainerPATCH 1/3 tracing: Constify struct event_trigger_ops
From: Christophe JAILLET <[email protected]>
[ Upstream commit 502d2e71a89fa706843fa9277f4d6de1947072c8 ]
'event_trigger_ops mwifiex_if_ops' are not modified in these drivers.
Constifying these structures moves some data to a read-only section, so increase overall security, especially when the structure holds some function pointers.
On a x86_64, with allmodconfig, as an example:
Before:
======
text data bss dec hex filename
31368 9024 6200 46592 b600 kernel/trace/trace_events_trigger.o
After:
=====
text data bss dec hex filename
31752 8608 6200 46560 b5e0 kernel/trace/trace_events_trigger.o
Stable-dep-of: 0fe23b8eaba0 ("tracing: Take the reference before publishing the named histogram trigger")
--- kernel/trace/trace.h | 4 +-- kernel/trace/trace_eprobe.c | 6 ++--- kernel/trace/trace_events_hist.c | 20 +++++++-------- kernel/trace/trace_events_trigger.c | 38 ++++++++++++++--------------- 4 files changed, 34 insertions(+), 34 deletions(-)
kernel/trace/trace.h +2 -2
@@ -1614,7 +1614,7 @@ struct event_trigger_data {unsigned long count;int ref;int flags; -struct event_trigger_ops *ops; +const struct event_trigger_ops *ops;struct event_command *cmd_ops;struct event_filter __rcu *filter;char *filter_str;
@@ -1857,7 +1857,7 @@ struct event_command {int (*set_filter)(char *filter_str,struct event_trigger_data *data,struct trace_event_file *file); -struct event_trigger_ops *(*get_trigger_ops)(char *cmd,char *param); +const struct event_trigger_ops *(*get_trigger_ops)(char *cmd,char *param); };/**
kernel/trace/trace_eprobe.c +3 -3
@@ -479,7 +479,7 @@ static void eprobe_trigger_func(struct event_trigger_data *data,__eprobe_trace_func (edata, rec); } -static struct event_trigger_ops eprobe_trigger_ops = { +static const struct event_trigger_ops eprobe_trigger_ops = { .trigger = eprobe_trigger_func, .print = eprobe_trigger_print, .init = eprobe_trigger_init,
@@ -508,8 +508,8 @@ static void eprobe_trigger_unreg_func(char *glob, } -static struct event_trigger_ops *eprobe_trigger_get_ops (char *cmd, -char *param) +static const struct event_trigger_ops *eprobe_trigger_get_ops (char *cmd, +char *param) {return &eprobe_trigger_ops; }
kernel/trace/trace_events_hist.c +10 -10
@@ -6334,7 +6334,7 @@ static void event_hist_trigger_free(struct event_trigger_data *data)free_hist_pad (); } -static struct event_trigger_ops event_hist_trigger_ops = { +static const struct event_trigger_ops event_hist_trigger_ops = { .trigger = event_hist_trigger, .print = event_hist_trigger_print, .init = event_hist_trigger_init,
@@ -6364,15 +6364,15 @@ static void event_hist_trigger_named_free(struct event_trigger_data *data) } } -static struct event_trigger_ops event_hist_trigger_named_ops = { +static const struct event_trigger_ops event_hist_trigger_named_ops = { .trigger = event_hist_trigger, .print = event_hist_trigger_print, .init = event_hist_trigger_named_init, .free = event_hist_trigger_named_free, }; -static struct event_trigger_ops *event_hist_get_trigger_ops (char *cmd, -char *param) +static const struct event_trigger_ops *event_hist_get_trigger_ops (char *cmd, +char *param) {return &event_hist_trigger_ops; }
@@ -6969,38 +6969,38 @@ hist_enable_count_trigger(struct event_trigger_data *data,hist_enable_trigger (data, buffer, rec, event); } -static struct event_trigger_ops hist_enable_trigger_ops = { +static const struct event_trigger_ops hist_enable_trigger_ops = { .trigger = hist_enable_trigger, .print = event_enable_trigger_print, .init = event_trigger_init, .free = event_enable_trigger_free, }; -static struct event_trigger_ops hist_enable_count_trigger_ops = { +static const struct event_trigger_ops hist_enable_count_trigger_ops = { .trigger = hist_enable_count_trigger, .print = event_enable_trigger_print, .init = event_trigger_init, .free = event_enable_trigger_free, }; -static struct event_trigger_ops hist_disable_trigger_ops = { +static const struct event_trigger_ops hist_disable_trigger_ops = { .trigger = hist_enable_trigger, .print = event_enable_trigger_print, .init = event_trigger_init, .free = event_enable_trigger_free, }; -static struct event_trigger_ops hist_disable_count_trigger_ops = { +static const struct event_trigger_ops hist_disable_count_trigger_ops = { .trigger = hist_enable_count_trigger, .print = event_enable_trigger_print, .init = event_trigger_init, .free = event_enable_trigger_free, }; -static struct event_trigger_ops * +static const struct event_trigger_ops *hist_enable_get_trigger_ops (char *cmd,char *param) { -struct event_trigger_ops *ops; +const struct event_trigger_ops *ops;bool enable; enable = (strcmp (cmd,ENABLE_HIST_STR ) ==0 );
kernel/trace/trace_events_trigger.c +19 -19
@@ -833,7 +833,7 @@ struct event_trigger_data *trigger_data_alloc(struct event_command *cmd_ops, void *private_data) {struct event_trigger_data *trigger_data; -struct event_trigger_ops *trigger_ops; +const struct event_trigger_ops *trigger_ops; trigger_ops = cmd_ops->get_trigger_ops (cmd, param);
@@ -1375,38 +1375,38 @@ traceoff_trigger_print(struct seq_file *m, struct event_trigger_data *data) data->filter_str); } -static struct event_trigger_ops traceon_trigger_ops = { +static const struct event_trigger_ops traceon_trigger_ops = { .trigger = traceon_trigger, .print = traceon_trigger_print, .init = event_trigger_init, .free = event_trigger_free, }; -static struct event_trigger_ops traceon_count_trigger_ops = { +static const struct event_trigger_ops traceon_count_trigger_ops = { .trigger = traceon_count_trigger, .print = traceon_trigger_print, .init = event_trigger_init, .free = event_trigger_free, }; -static struct event_trigger_ops traceoff_trigger_ops = { +static const struct event_trigger_ops traceoff_trigger_ops = { .trigger = traceoff_trigger, .print = traceoff_trigger_print, .init = event_trigger_init, .free = event_trigger_free, }; -static struct event_trigger_ops traceoff_count_trigger_ops = { +static const struct event_trigger_ops traceoff_count_trigger_ops = { .trigger = traceoff_count_trigger, .print = traceoff_trigger_print, .init = event_trigger_init, .free = event_trigger_free, }; -static struct event_trigger_ops * +static const struct event_trigger_ops *onoff_get_trigger_ops (char *cmd,char *param) { -struct event_trigger_ops *ops; +const struct event_trigger_ops *ops;/* we register both traceon and traceoff to this callback */ if (strcmp (cmd,"traceon" ) ==0 )
@@ -1488,21 +1488,21 @@ snapshot_trigger_print(struct seq_file *m, struct event_trigger_data *data) data->filter_str); } -static struct event_trigger_ops snapshot_trigger_ops = { +static const struct event_trigger_ops snapshot_trigger_ops = { .trigger = snapshot_trigger, .print = snapshot_trigger_print, .init = event_trigger_init, .free = event_trigger_free, }; -static struct event_trigger_ops snapshot_count_trigger_ops = { +static const struct event_trigger_ops snapshot_count_trigger_ops = { .trigger = snapshot_count_trigger, .print = snapshot_trigger_print, .init = event_trigger_init, .free = event_trigger_free, }; -static struct event_trigger_ops * +static const struct event_trigger_ops *snapshot_get_trigger_ops (char *cmd,char *param) {return param ? &snapshot_count_trigger_ops : &snapshot_trigger_ops;
@@ -1583,21 +1583,21 @@ stacktrace_trigger_print(struct seq_file *m, struct event_trigger_data *data) data->filter_str); } -static struct event_trigger_ops stacktrace_trigger_ops = { +static const struct event_trigger_ops stacktrace_trigger_ops = { .trigger = stacktrace_trigger, .print = stacktrace_trigger_print, .init = event_trigger_init, .free = event_trigger_free, }; -static struct event_trigger_ops stacktrace_count_trigger_ops = { +static const struct event_trigger_ops stacktrace_count_trigger_ops = { .trigger = stacktrace_count_trigger, .print = stacktrace_trigger_print, .init = event_trigger_init, .free = event_trigger_free, }; -static struct event_trigger_ops * +static const struct event_trigger_ops *stacktrace_get_trigger_ops (char *cmd,char *param) {return param ? &stacktrace_count_trigger_ops : &stacktrace_trigger_ops;
@@ -1708,28 +1708,28 @@ void event_enable_trigger_free(struct event_trigger_data *data) } } -static struct event_trigger_ops event_enable_trigger_ops = { +static const struct event_trigger_ops event_enable_trigger_ops = { .trigger = event_enable_trigger, .print = event_enable_trigger_print, .init = event_trigger_init, .free = event_enable_trigger_free, }; -static struct event_trigger_ops event_enable_count_trigger_ops = { +static const struct event_trigger_ops event_enable_count_trigger_ops = { .trigger = event_enable_count_trigger, .print = event_enable_trigger_print, .init = event_trigger_init, .free = event_enable_trigger_free, }; -static struct event_trigger_ops event_disable_trigger_ops = { +static const struct event_trigger_ops event_disable_trigger_ops = { .trigger = event_enable_trigger, .print = event_enable_trigger_print, .init = event_trigger_init, .free = event_enable_trigger_free, }; -static struct event_trigger_ops event_disable_count_trigger_ops = { +static const struct event_trigger_ops event_disable_count_trigger_ops = { .trigger = event_enable_count_trigger, .print = event_enable_trigger_print, .init = event_trigger_init,
@@ -1913,10 +1913,10 @@ void event_enable_unregister_trigger(char *glob, data->ops->free (data); } -static struct event_trigger_ops * +static const struct event_trigger_ops *event_enable_get_trigger_ops (char *cmd,char *param) { -struct event_trigger_ops *ops; +const struct event_trigger_ops *ops;bool enable;#ifdef CONFIG_HIST_TRIGGERS
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/3 tracing: Merge struct event_trigger_ops into struct event_command
From: Steven Rostedt <[email protected]>
[ Upstream commit b052d70f7c9c156409a70e65c10d83b5650e7e78 ]
Now that there's pretty much a one to one mapping between the struct event_trigger_ops and struct event_command, there's no reason to have two different structures. Merge the function pointers of event_trigger_ops into event_command.
There's one exception in trace_events_hist.c for the event_hist_trigger_named_ops. This has special logic for the init and free function pointers for "named histograms". In this case, allocate the cmd_ops of the event_trigger_data and set it to the proper init and free functions, which are used to initialize and free the event_trigger_data respectively. Have the free function and the init function (on failure) free the cmd_ops of the data element.
Stable backport note: Linux 6.6 still uses get_trigger_ops() to select separate counted and uncounted trigger implementations. Limit this preparatory merge to the init/free lifecycle callbacks and retain the existing trigger/print dispatch in event_trigger_ops. Move every lifecycle initializer and caller to event_command, including eprobes and histogram enable/disable commands.
Keep the upstream allocation, initialization-failure cleanup, and teardown of private command operations for named histograms. This supplies the context needed by commit 0fe23b8eaba0 ("tracing: Take the reference before publishing the named histogram trigger") without importing the missing counting and unregister refactors or adding any functions.
Stable-dep-of: 0fe23b8eaba0 ("tracing: Take the reference before publishing the named histogram trigger")
--- kernel/trace/trace.h | 49 ++++++++++------------ kernel/trace/trace_eprobe.c | 4 +- kernel/trace/trace_events_hist.c | 65 +++++++++++++++++------------ kernel/trace/trace_events_trigger.c | 60 +++++++++++--------------- 4 files changed, 86 insertions(+), 92 deletions(-)
kernel/trace/trace.h +22 -27
@@ -1707,18 +1707,13 @@ extern void event_file_put(struct trace_event_file *file);* The methods in this structure provide per-event trigger hooks for * various trigger operations. * -* The @init and @free methods are used during trigger setup and -* teardown, typically called from an event_command's @parse() -* function implementation. -* * The @print method is used to print the trigger spec. * * The @trigger method is the function that actually implements the * trigger and is called in the context of the triggering event * whenever that event occurs. * -* All the methods below, except for @init() and @free(), must be -* implemented. +* All the methods below must be implemented. * * @trigger: The trigger 'probe' function called when the triggering * event occurs. The data passed into this callback is the data
@@ -1726,23 +1721,6 @@ extern void event_file_put(struct trace_event_file *file);* registered the trigger (see struct event_command) along with * the trace record, rec. * -* @init: An optional initialization function called for the trigger -* when the trigger is registered (via the event_command reg() -* function). This can be used to perform per-trigger -* initialization such as incrementing a per-trigger reference -* count, for instance. This is usually implemented by the -* generic utility function @event_trigger_init() (see -* trace_event_triggers.c). -* -* @free: An optional de-initialization function called for the -* trigger when the trigger is unregistered (via the -* event_command @reg() function). This can be used to perform -* per-trigger de-initialization such as decrementing a -* per-trigger reference count and freeing corresponding trigger -* data, for instance. This is usually implemented by the -* generic utility function @event_trigger_free() (see -* trace_event_triggers.c). -* * @print: The callback function invoked to have the trigger print * itself. This is usually implemented by a wrapper function * that calls the generic utility function @event_trigger_print()
@@ -1753,8 +1731,6 @@ struct event_trigger_ops {struct trace_buffer *buffer, void *rec, struct ring_buffer_event *rbe); -int (*init)(struct event_trigger_data *data); -void (*free)(struct event_trigger_data *data);int (*print)(struct seq_file *m,struct event_trigger_data *data); };
@@ -1808,7 +1784,7 @@ struct event_trigger_ops {* * @reg: Adds the trigger to the list of triggers associated with the * event, and enables the event trigger itself, after -* initializing it (via the event_trigger_ops @init() function). +* initializing it (via the event_command @init() function). * This is also where commands can use the @trigger_type value to * make the decision as to whether or not multiple instances of * the trigger should be allowed. This is usually implemented by
@@ -1817,7 +1793,7 @@ struct event_trigger_ops {* * @unreg: Removes the trigger from the list of triggers associated * with the event, and disables the event trigger itself, after -* initializing it (via the event_trigger_ops @free() function). +* initializing it (via the event_command @free() function). * This is usually implemented by the generic utility function * @unregister_trigger() (see trace_event_triggers.c). *
@@ -1837,6 +1813,23 @@ struct event_trigger_ops {* support multiple trigger implementations via different sets of * event_trigger_ops, depending on the value of the @param * string. +* +* @init: An optional initialization function called for the trigger +* when the trigger is registered (via the event_command reg() +* function). This can be used to perform per-trigger +* initialization such as incrementing a per-trigger reference +* count, for instance. This is usually implemented by the +* generic utility function @event_trigger_init() (see +* trace_event_triggers.c). +* +* @free: An optional de-initialization function called for the +* trigger when the trigger is unregistered (via the +* event_command @reg() function). This can be used to perform +* per-trigger de-initialization such as decrementing a +* per-trigger reference count and freeing corresponding trigger +* data, for instance. This is usually implemented by the +* generic utility function @event_trigger_free() (see +* trace_event_triggers.c). */ struct event_command {struct list_head list;
@@ -1858,6 +1851,8 @@ struct event_command {struct event_trigger_data *data, struct trace_event_file *file);const struct event_trigger_ops *(*get_trigger_ops)(char *cmd,char *param); +int (*init)(struct event_trigger_data *data); +void (*free)(struct event_trigger_data *data); };/**
kernel/trace/trace_eprobe.c +2 -2
@@ -482,8 +482,6 @@ static void eprobe_trigger_func(struct event_trigger_data *data,static const struct event_trigger_ops eprobe_trigger_ops = { .trigger = eprobe_trigger_func, .print = eprobe_trigger_print, - .init = eprobe_trigger_init, - .free = eprobe_trigger_free, }; static int eprobe_trigger_cmd_parse(struct event_command *cmd_ops,
@@ -524,6 +522,8 @@ static struct event_command event_trigger_cmd = { .unreg_all = NULL, .get_trigger_ops = eprobe_trigger_get_ops, .set_filter = NULL, + .init = eprobe_trigger_init, + .free = eprobe_trigger_free, }; static struct event_trigger_data *
kernel/trace/trace_events_hist.c +38 -27
157 lines not on this page · raw message
kernel/trace/trace_events_trigger.c +24 -36
202 lines not on this page · raw message
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/3 tracing: Take the reference before publishing the named histogram trigger
In reply to Sasha LevinFrom: Donggeun Yoo <[email protected]>
[ Upstream commit 0fe23b8eaba0d3372c66b7b31204408da0715edc ]
event_hist_trigger_named_init() puts the trigger on the global named_triggers list and only then takes the reference on the trigger it shares its histogram with:
data->ref++;
save_named_trigger(data->named_data->name, data);
ret = event_hist_trigger_init(data->named_data);
if (ret < 0) {
kfree(data->cmd_ops);
data->cmd_ops = &trigger_hist_cmd;
}
return ret;event_hist_trigger_init() fails when alloc_hist_pad() cannot allocate, and nothing takes the trigger back off the list on the way out. event_hist_trigger_parse() frees it, and the next lookup by name reads the freed object:
BUG: KASAN: slab-use-after-free in find_named_trigger+0xac/0xc0 Read of size 8 at addr ffff888009346860 by task init/1 find_named_trigger+0xac/0xc0 hist_register_trigger+0xc1/0xa00 event_hist_trigger_parse+0x3146/0x6af0 event_trigger_write+0xce/0x160 Freed by task 67: kfree+0x154/0x420 trigger_kthread_fn+0xfd/0x160
Do the reference first and publish once it has succeeded, so that nothing which can fail runs after the trigger becomes findable.
--- kernel/trace/trace_events_hist.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
kernel/trace/trace_events_hist.c +6 -5
@@ -6343,17 +6343,18 @@ static int event_hist_trigger_named_init(struct event_trigger_data *data) {int ret; - data->ref++; - -save_named_trigger (data->named_data->name, data); - ret =event_hist_trigger_init (data->named_data);if (ret <0 ) {kfree (data->cmd_ops); data->cmd_ops = &trigger_hist_cmd; +return ret; } -return ret; + data->ref++; + +save_named_trigger (data->named_data->name, data); + +return 0 ; }static void event_hist_trigger_named_free (struct event_trigger_data *data)
Signature · 1 line
2.53.0