[PATCH v3 10/16] tracing/filters: Reject unsupported field sizes in parse_pred()

From: Masami Hiramatsu (Google)

Date: Tue Oct 27 2026 - 20:46:59 EST


From: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>

Prior to commit 80765597bc58 ("tracing: Rewrite filter logic to be simpler
and faster"), parse_pred() checked whether select_comparison_fn() returned
NULL and failed with FILT_ERR_INVALID_OP and -EINVAL. That check was lost
during the rewrite, and commit 3cbec9d7b93d ("tracing/filters: Enable
filtering a scalar field by a cpumask") similarly omitted a default error
case when matching field->size for CPUS{} comparisons.

If a non-string field (FILTER_OTHER) has a size other than 1, 2, 4, or 8
(such as a fixed-size integer array field), pred->fn_num remains
FILTER_PRED_FN_NOP (0) and parse_pred() returns success. Subsequently,
update_preds() rejects FILTER_PRED_FN_NOP via WARN_ON_ONCE() and returns
-EINVAL without setting a parse_error() message, triggering a kernel
warning from user-supplied filter input.

Restore the check for FILTER_PRED_FN_NOP in both the numeric scalar and
CPUS{} branches of parse_pred() and report FILT_ERR_INVALID_OP.

Fixes: 80765597bc58 ("tracing: Rewrite filter logic to be simpler and faster")
Fixes: 3cbec9d7b93d ("tracing/filters: Enable filtering a scalar field by a cpumask")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>
---
kernel/trace/trace_events_filter.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 48e16d75be74..9d1446464058 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -2015,6 +2015,10 @@ static int parse_pred(const char *str, void *data,
break;
}
}
+ if (pred->fn_num == FILTER_PRED_FN_NOP) {
+ parse_error(pe, FILT_ERR_INVALID_OP, pos + i);
+ goto err_free;
+ }

/* This is either a string, or an integer */
} else if (str[i] == '\'' || str[i] == '"') {
@@ -2164,6 +2168,10 @@ static int parse_pred(const char *str, void *data,
else {
pred->fn_num = select_comparison_fn(pred->op, field->size,
field->is_signed);
+ if (pred->fn_num == FILTER_PRED_FN_NOP) {
+ parse_error(pe, FILT_ERR_INVALID_OP, pos + i);
+ goto err_free;
+ }
if (pred->op == OP_NE)
pred->not = 1;
}