[STABLE v6.1-v5.10] tracing/histograms: Reject non-stacktrace fields for synthetic stacktrace fields

From: Lee Jones

Date: Mon Oct 26 2026 - 10:24:05 EST


[ Upstream commit a244c241593b5b38a08f0df2cb43c26574efbdcb ]

In check_synth_field(), when a synthetic event field is a stacktrace
(field->is_stack) and the histogram field is not a "long[" stacktrace
array, validation falls through to the generic size and signedness
comparison.

Because parse_synth_field() sets a stacktrace field's type to
"__data_loc unsigned long[]", its size is sizeof(u64) and
synth_field_signed() marks it as signed. Consequently, any 8-byte
signed scalar histogram field passes the fallback check, and its scalar
value is subsequently dereferenced as a kernel stacktrace pointer in
get_field_size() and trace_stack().

Furthermore, checking strstr(hist_field->type, "long[") is insufficient
because tracepoint fields defined with __bitmask() or __rel_bitmask()
also have type "__data_loc unsigned long[]" or "__rel_loc unsigned
long[]", whilst create_hist_field() treats them as 4-byte scalar values
without HIST_FIELD_FL_STACKTRACE.

Propagate HIST_FIELD_FL_STACKTRACE to variable references and field
variables (whilst excluding variable aliases from per-element
stacktrace capture), and reject any mismatch between
HIST_FIELD_FL_STACKTRACE and field->is_stack in check_synth_field().

Cc: stable@xxxxxxxxxxxxxxx
Fixes: 00cf3d672a9d ("tracing: Allow synthetic events to pass around stacktraces")
Link: https://patch.msgid.link/20261013112449.1006088-1-lee@xxxxxxxxxx
Signed-off-by: Lee Jones <lee@xxxxxxxxxx>
Acked-by: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>
Signed-off-by: Steven Rostedt <rostedt@xxxxxxxxxxx>
[Lee: Omit create_var_field() and hist_trigger_elt_update() hunks as
288709c9f3b0 ("tracing: Allow stacktraces to be saved as histogram
variables") is not present]
Signed-off-by: Lee Jones <lee@xxxxxxxxxx>
---
kernel/trace/trace_events_hist.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace_events_hist.c b/kernel/trace/trace_events_hist.c
index 8e5efdfa0fc7..b8fb45fa3cfc 100644
--- a/kernel/trace/trace_events_hist.c
+++ b/kernel/trace/trace_events_hist.c
@@ -2066,7 +2066,8 @@ static int init_var_ref(struct hist_field *ref_field,
ref_field->size = var_field->size;
ref_field->is_signed = var_field->is_signed;
ref_field->flags |= var_field->flags &
- (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS);
+ (HIST_FIELD_FL_TIMESTAMP | HIST_FIELD_FL_TIMESTAMP_USECS |
+ HIST_FIELD_FL_STACKTRACE);

if (system) {
ref_field->system = kstrdup(system, GFP_KERNEL);
@@ -3203,6 +3204,7 @@ static struct field_var *create_field_var(struct hist_trigger_data *hist_data,
ret = -ENOMEM;
goto err;
}
+ var->flags |= val->flags & HIST_FIELD_FL_STACKTRACE;

field_var->var = var;
field_var->val = val;
@@ -3820,7 +3822,10 @@ static int check_synth_field(struct synth_event *event,
&& field->is_dynamic)
return 0;

- if (strstr(hist_field->type, "long[") && field->is_stack)
+ if (!!(hist_field->flags & HIST_FIELD_FL_STACKTRACE) != field->is_stack)
+ return -EINVAL;
+
+ if (field->is_stack)
return 0;

if (strcmp(field->type, hist_field->type) != 0) {
--
2.56.0.257.gf7497c7d27-goog