FAILED: patch "[PATCH] tracing: Fix NULL dereference when copying keys for a field" failed to apply to 6.18-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.18-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.18.y
git checkout FETCH_HEAD
git cherry-pick -x a0777b9e53157f1f6848a0fd0650f5465391ea81
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026102122-spinster-handler-2d56@gregkh' --subject-prefix 'PATCH 6.18.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From a0777b9e53157f1f6848a0fd0650f5465391ea81 Mon Sep 17 00:00:00 2001
From: Donggeun Yoo <[email protected]>
Date: Mon, 14 Sep 2026 14:34:43 +0900
Subject: [PATCH] tracing: Fix NULL dereference when copying keys for a field
variable
In event_hist_trigger_parse() where it needs to create actions like "onmatch", it calls:
event_hist_trigger_parse() {
create_actions() {
action_create() {
trace_action_create() {
trace_action_create_field_var() {
create_field_var_hist()Where create_field_var_hist() does a loop on the hist_data representing the keys. The issue is, if the keys uses one of the pseudo field types (like common_cpu), the hist_data field element will have NULL for its field member causing a NULL pointer dereference when accessing the key_field->field->name.
# echo 'hist:keys=common_cpu:ts0=common_timestamp.usecs' > \
events/sched/sched_waking/trigger
# echo 'my_synth u64 lat; int prio' > synthetic_events
# echo 'hist:keys=common_cpu:wakeup_lat=common_timestamp.usecs-$ts0:\
onmatch(sched.sched_waking).my_synth($wakeup_lat,prio)' > \
events/sched/sched_switch/triggerKASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017] RIP: 0010:create_field_var_hist+0x771/0x1380 Call Trace: trace_action_create_field_var+0x360/0x600 trace_action_create+0x393/0xe80 event_hist_trigger_parse+0x3e47/0x69e0 trigger_process_regex+0x1a6/0x250 event_trigger_write+0xce/0x160
Instead of accessing it directly, use the proper handler expr_field_str() to get the name.
The three previous patches are prerequisites: without them a .buckets key and a common_stacktrace key each render into a command that cannot be parsed back.
kernel/trace/trace_events_hist.c +1 -1
@@ -3090,7 +3090,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data, key_field = hist_data->fields[i];if (!first)seq_buf_putc (&s,',' ); -seq_buf_puts (&s, key_field->field->name); +expr_field_str (key_field, &s); first = false; }
Sasha Levin
maintainerPATCH 1/4 tracing: Fix fully-qualified variable reference printing in histograms
From: Tom Zanussi <[email protected]>
[ Upstream commit 9236eebd138aa2753f7b30fc6cee7b7202841247 ]
The syntax for fully-qualified variable references in histograms is subsys.event.$var, which is parsed correctly, but not displayed correctly when printing a histogram spec. The current code puts the $ reference at the beginning of the fully-qualified variable name i.e. $subsys.event.var, which is incorrect.
Before:
trigger info: hist:keys=next_comm:vals=hitcount:wakeup_lat=common_timestamp.usecs-$sched.sched_wakeup.ts0: ...
After:
trigger info: hist:keys=next_comm:vals=hitcount:wakeup_lat=common_timestamp.usecs-sched.sched_wakeup.$ts0: ...
Stable-dep-of: a0777b9e5315 ("tracing: Fix NULL dereference when copying keys for a field variable")
--- kernel/trace/trace_events_hist.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
kernel/trace/trace_events_hist.c +10 -5
@@ -1355,9 +1355,12 @@ static const char *hist_field_name(struct hist_field *field, field->flags & HIST_FIELD_FL_VAR_REF) {if (field->system) {static char full_name[MAX_FILTER_STR_VAL ]; +static char *fmt;int len; - len =snprintf (full_name,sizeof (full_name),"%s.%s.%s" , + fmt = field->flags &HIST_FIELD_FL_VAR_REF ?"%s.%s.$%s" :"%s.%s.%s" ; + + len =snprintf (full_name,sizeof (full_name), fmt, field->system, field->event_name, field->name);if (len <sizeof (full_name))
@@ -1734,9 +1737,10 @@ static const char *get_hist_field_flags(struct hist_field *hist_field)static void expr_field_str (struct hist_field *field,char *expr) { -if (field->flags &HIST_FIELD_FL_VAR_REF ) -strcat (expr,"$" ); -else if (field->flags &HIST_FIELD_FL_CONST ) { +if (field->flags &HIST_FIELD_FL_VAR_REF ) { +if (!field->system) +strcat (expr,"$" ); + }else if (field->flags &HIST_FIELD_FL_CONST ) {char str[HIST_CONST_DIGITS_MAX ];snprintf (str,HIST_CONST_DIGITS_MAX ,"%llu" , field->constant);
@@ -6167,7 +6171,8 @@ static void hist_field_print(struct seq_file *m, struct hist_field *hist_field)else if (field_name) {if (hist_field->flags &HIST_FIELD_FL_VAR_REF || hist_field->flags &HIST_FIELD_FL_ALIAS ) -seq_putc (m,'$' ); +if (!hist_field->system) +seq_putc (m,'$' );seq_printf (m,"%s" , field_name); }else if (hist_field->flags &HIST_FIELD_FL_TIMESTAMP )seq_puts (m,"common_timestamp" );
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 2/4 tracing: Use __free() for expr_str() buffer
From: Pengpeng Hou <[email protected]>
[ Upstream commit 988995c0552b6213b6bf16cea57258d4842c1488 ]
expr_str() allocates a temporary expression buffer and manually frees it on some error paths.
Convert the buffer to __free(kfree) and return it with return_ptr() on success. This keeps ownership handling separate from the later ERR_PTR() conversion and string-bound change.
Stable-dep-of: a0777b9e5315 ("tracing: Fix NULL dereference when copying keys for a field variable")
--- kernel/trace/trace_events_hist.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-)
kernel/trace/trace_events_hist.c +6 -8
@@ -1761,7 +1761,7 @@ static void expr_field_str(struct hist_field *field, char *expr)static char *expr_str (struct hist_field *field,unsigned int level) { -char *expr; + char *expr __free(kfree) = NULL;if (level >1 )return NULL ;
@@ -1772,7 +1772,7 @@ static char *expr_str(struct hist_field *field, unsigned int level)if (!field->operands[0 ]) {expr_field_str (field, expr); -return expr; +return_ptr (expr); }if (field->operator ==FIELD_OP_UNARY_MINUS ) {
@@ -1780,16 +1780,15 @@ static char *expr_str(struct hist_field *field, unsigned int level)strcat (expr,"-(" ); subexpr =expr_str (field->operands[0 ], ++level); -if (!subexpr) { -kfree (expr); +if (!subexpr)return NULL ; - } +strcat (expr, subexpr);strcat (expr,")" );kfree (subexpr); -return expr; +return_ptr (expr); }expr_field_str (field->operands[0 ], expr);
@@ -1808,13 +1807,12 @@ static char *expr_str(struct hist_field *field, unsigned int level)strcat (expr,"*" );break ;default : -kfree (expr);return NULL ; }expr_field_str (field->operands[1 ], expr); -return expr; +return_ptr (expr); }/*
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 3/4 tracing: Bound histogram expression strings with seq_buf
In reply to Sasha LevinFrom: Pengpeng Hou <[email protected]>
[ Upstream commit 935601a4276f28105498609f7f98aa66e86e9c96 ]
expr_str() allocates a fixed MAX_FILTER_STR_VAL buffer and then builds expression names with a series of raw strcat() appends. Nested operands, constants, field flags, and generated field names can push the rendered string past that fixed limit before the name is attached to the hist field.
Build expression strings with seq_buf and return -E2BIG when the rendered name would exceed MAX_FILTER_STR_VAL. This keeps the existing tracing-side limit while replacing the raw append logic with bounded construction.
Stable-dep-of: a0777b9e5315 ("tracing: Fix NULL dereference when copying keys for a field variable")
--- kernel/trace/trace_events_hist.c | 57 ++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 24 deletions(-)
kernel/trace/trace_events_hist.c +33 -24
@@ -94,7 +94,6 @@ typedef u64 (*hist_field_fn_t) (struct hist_field *field,#define HIST_FIELD_OPERANDS_MAX 2#define HIST_FIELDS_MAX (TRACING_MAP_FIELDS_MAX + TRACING_MAP_VARS_MAX)#define HIST_ACTIONS_MAX 8 -#define HIST_CONST_DIGITS_MAX 21#define HIST_DIV_SHIFT 20/* For optimizing division by constants */ enum field_op_id {
@@ -1735,33 +1734,36 @@ static const char *get_hist_field_flags(struct hist_field *hist_field)return flags_str; } -static void expr_field_str (struct hist_field *field,char *expr) +static bool expr_field_str (struct hist_field *field,struct seq_buf *s) { +const char *field_name; +if (field->flags &HIST_FIELD_FL_VAR_REF ) {if (!field->system) -strcat (expr,"$" ); - }else if (field->flags &HIST_FIELD_FL_CONST ) { -char str[HIST_CONST_DIGITS_MAX ]; +seq_buf_putc (s,'$' ); + }else if (field->flags &HIST_FIELD_FL_CONST ) +seq_buf_printf (s,"%llu" , field->constant); -snprintf (str,HIST_CONST_DIGITS_MAX ,"%llu" , field->constant); -strcat (expr, str); - } + field_name =hist_field_name (field,0 ); +if (!field_name) +return false; -strcat (expr,hist_field_name (field,0 )); +seq_buf_puts (s, field_name);if (field->flags && !(field->flags &HIST_FIELD_FL_VAR_REF )) {const char *flags_str =get_hist_field_flags (field); -if (flags_str) { -strcat (expr,"." ); -strcat (expr, flags_str); - } +if (flags_str) +seq_buf_printf (s,".%s" , flags_str); } + +return !seq_buf_has_overflowed (s); }static char *expr_str (struct hist_field *field,unsigned int level) { char *expr __free(kfree) = NULL; +struct seq_buf s;if (level >1 )return NULL ;
@@ -1770,47 +1772,54 @@ static char *expr_str(struct hist_field *field, unsigned int level)if (!expr)return NULL ; +seq_buf_init (&s, expr,MAX_FILTER_STR_VAL ); +if (!field->operands[0 ]) { -expr_field_str (field, expr); +if (!expr_field_str (field, &s)) +return ERR_PTR (-E2BIG ); +return_ptr (expr); }if (field->operator ==FIELD_OP_UNARY_MINUS ) {char *subexpr; -strcat (expr,"-(" ); subexpr =expr_str (field->operands[0 ], ++level);if (!subexpr)return NULL ; -strcat (expr, subexpr); -strcat (expr,")" ); - +seq_buf_printf (&s,"-(%s)" , subexpr);kfree (subexpr); +if (seq_buf_has_overflowed (&s)) +return ERR_PTR (-E2BIG ); +return_ptr (expr); } -expr_field_str (field->operands[0 ], expr); +if (!expr_field_str (field->operands[0 ], &s)) +return ERR_PTR (-E2BIG );switch (field->operator) {case FIELD_OP_MINUS : -strcat (expr,"-" ); +seq_buf_putc (&s,'-' );break ;case FIELD_OP_PLUS : -strcat (expr,"+" ); +seq_buf_putc (&s,'+' );break ;case FIELD_OP_DIV : -strcat (expr,"/" ); +seq_buf_putc (&s,'/' );break ;case FIELD_OP_MULT : -strcat (expr,"*" ); +seq_buf_putc (&s,'*' );break ;default :return NULL ; } -expr_field_str (field->operands[1 ], expr); +if (seq_buf_has_overflowed (&s) || + !expr_field_str (field->operands[1 ], &s)) +return ERR_PTR (-E2BIG );return_ptr (expr); }
Signature · 1 line
2.53.0
Sasha Levin
maintainerPATCH 4/4 tracing: Fix NULL dereference when copying keys for a field variable
In reply to Sasha LevinFrom: Donggeun Yoo <[email protected]>
[ Upstream commit a0777b9e53157f1f6848a0fd0650f5465391ea81 ]
In event_hist_trigger_parse() where it needs to create actions like "onmatch", it calls:
event_hist_trigger_parse() {
create_actions() {
action_create() {
trace_action_create() {
trace_action_create_field_var() {
create_field_var_hist()Where create_field_var_hist() does a loop on the hist_data representing the keys. The issue is, if the keys uses one of the pseudo field types (like common_cpu), the hist_data field element will have NULL for its field member causing a NULL pointer dereference when accessing the key_field->field->name.
# echo 'hist:keys=common_cpu:ts0=common_timestamp.usecs' > \
events/sched/sched_waking/trigger
# echo 'my_synth u64 lat; int prio' > synthetic_events
# echo 'hist:keys=common_cpu:wakeup_lat=common_timestamp.usecs-$ts0:\
onmatch(sched.sched_waking).my_synth($wakeup_lat,prio)' > \
events/sched/sched_switch/triggerKASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017] RIP: 0010:create_field_var_hist+0x771/0x1380 Call Trace: trace_action_create_field_var+0x360/0x600 trace_action_create+0x393/0xe80 event_hist_trigger_parse+0x3e47/0x69e0 trigger_process_regex+0x1a6/0x250 event_trigger_write+0xce/0x160
Instead of accessing it directly, use the proper handler expr_field_str() to get the name.
The three previous patches are prerequisites: without them a .buckets key and a common_stacktrace key each render into a command that cannot be parsed back.
--- kernel/trace/trace_events_hist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/trace/trace_events_hist.c +1 -1
@@ -3081,7 +3081,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data, key_field = hist_data->fields[i];if (!first)seq_buf_putc (&s,',' ); -seq_buf_puts (&s, key_field->field->name); +expr_field_str (key_field, &s); first = false; }
Signature · 1 line
2.53.0