]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tracing: Bound synthetic-field strings with seq_buf
authorPengpeng Hou <pengpeng@iscas.ac.cn>
Thu, 30 Apr 2026 04:33:50 +0000 (12:33 +0800)
committerSteven Rostedt <rostedt@goodmis.org>
Thu, 21 May 2026 22:03:06 +0000 (18:03 -0400)
The synthetic field helpers build a prefixed synthetic variable name and
a generated hist command in fixed MAX_FILTER_STR_VAL buffers. The
current code appends those strings with raw strcat(), so long key lists,
field names, or saved filters can run past the end of the staging
buffers.

Build both strings with seq_buf and propagate -E2BIG if either the
synthetic variable name or the generated command exceeds
MAX_FILTER_STR_VAL. This keeps the existing tracing-side limit while
using the helper intended for bounded command construction.

Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Tom Zanussi <tom.zanussi@linux.intel.com>
Link: https://patch.msgid.link/20260430043350.57928-1-pengpeng@iscas.ac.cn
Fixes: 02205a6752f2 ("tracing: Add support for 'field variables'")
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Reviewed-by: Tom Zanussi <zanussi@kernel.org>
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
[ sdr: Moved struct seq_buf *s for upside-down x-mas tree formatting ]
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
kernel/trace/trace_events_hist.c

index eb2c2bc8bc3d52e6d35fc72c1d0a5878f7bf04fc..9701650c89b2f240efb1b311cd21ee022aad42bd 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/kallsyms.h>
 #include <linux/security.h>
+#include <linux/seq_buf.h>
 #include <linux/mutex.h>
 #include <linux/slab.h>
 #include <linux/stacktrace.h>
@@ -2967,13 +2968,22 @@ find_synthetic_field_var(struct hist_trigger_data *target_hist_data,
 {
        struct hist_field *event_var;
        char *synthetic_name;
+       struct seq_buf s;
 
        synthetic_name = kzalloc(MAX_FILTER_STR_VAL, GFP_KERNEL);
        if (!synthetic_name)
                return ERR_PTR(-ENOMEM);
 
-       strcpy(synthetic_name, "synthetic_");
-       strcat(synthetic_name, field_name);
+       seq_buf_init(&s, synthetic_name, MAX_FILTER_STR_VAL);
+       seq_buf_printf(&s, "synthetic_%s", field_name);
+
+       /* Terminate synthetic_name with a NUL. */
+       seq_buf_str(&s);
+
+       if (seq_buf_has_overflowed(&s)) {
+               kfree(synthetic_name);
+               return ERR_PTR(-E2BIG);
+       }
 
        event_var = find_event_var(target_hist_data, system, event_name, synthetic_name);
 
@@ -3019,6 +3029,7 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
        struct hist_field *key_field;
        struct hist_field *event_var;
        char *saved_filter;
+       struct seq_buf s;
        char *cmd;
        int ret;
 
@@ -3063,28 +3074,34 @@ create_field_var_hist(struct hist_trigger_data *target_hist_data,
                return ERR_PTR(-ENOMEM);
        }
 
+       seq_buf_init(&s, cmd, MAX_FILTER_STR_VAL);
+
        /* Use the same keys as the compatible histogram */
-       strcat(cmd, "keys=");
+       seq_buf_puts(&s, "keys=");
 
        for_each_hist_key_field(i, hist_data) {
                key_field = hist_data->fields[i];
                if (!first)
-                       strcat(cmd, ",");
-               strcat(cmd, key_field->field->name);
+                       seq_buf_putc(&s, ',');
+               seq_buf_puts(&s, key_field->field->name);
                first = false;
        }
 
        /* Create the synthetic field variable specification */
-       strcat(cmd, ":synthetic_");
-       strcat(cmd, field_name);
-       strcat(cmd, "=");
-       strcat(cmd, field_name);
+       seq_buf_printf(&s, ":synthetic_%s=%s", field_name, field_name);
 
        /* Use the same filter as the compatible histogram */
        saved_filter = find_trigger_filter(hist_data, file);
-       if (saved_filter) {
-               strcat(cmd, " if ");
-               strcat(cmd, saved_filter);
+       if (saved_filter)
+               seq_buf_printf(&s, " if %s", saved_filter);
+
+       /* Terminate cmd with a NUL. */
+       seq_buf_str(&s);
+
+       if (seq_buf_has_overflowed(&s)) {
+               kfree(cmd);
+               kfree(var_hist);
+               return ERR_PTR(-E2BIG);
        }
 
        var_hist->cmd = kstrdup(cmd, GFP_KERNEL);