On Fri, 23 Oct 2026 10:46:20 -0700, Kyle Zeng <[email protected]> wrote: > A non-empty expression normally finishes in predicate_parse()'s inner > loop, which resolves the pending logical operators before jumping to > finalization. If the input ends after an operator, possibly followed by > unary '!' tokens, the outer loop instead falls through with unresolved > operator state. > > For example, "common_pid == 1 || common_pid == 2 &&" leaves > prog[0].target equal to -1. The second pass then reads prog[-1] before > the forward-jump check can reject it. Depending on adjacent slab > contents, it can also copy an out-of-bounds word into a branch target > that passes the forward-only check. A self-targeted perf tracepoint > counting event can reach this path through PERF_EVENT_IOC_SET_FILTER. > > Reject the outer-loop fallthrough when a predicate has already been > parsed. This ensures that non-empty expressions only reach finalization > after the inner loop has resolved their operators. Keep the existing > no-filter error for input that has no predicates. Add a regression test > for trailing logical operators and unary negations. >
Looks good to me. Acked-by: Masami Hiramatsu (Google) <[email protected]> Thanks! > Fixes: 80765597bc587 ("tracing: Rewrite filter logic to be simpler and > faster") > Cc: [email protected] > Assisted-by: Codex:gpt-6-astra > Signed-off-by: Kyle Zeng <[email protected]> > --- > kernel/trace/trace_events_filter.c | 6 +++++ > .../test.d/filter/event-filter-incomplete.tc | 24 +++++++++++++++++++ > 2 files changed, 30 insertions(+) > create mode 100644 > tools/testing/selftests/ftrace/test.d/filter/event-filter-incomplete.tc > > diff --git a/kernel/trace/trace_events_filter.c > b/kernel/trace/trace_events_filter.c > index 2b46ca536045..405651be9c93 100644 > --- a/kernel/trace/trace_events_filter.c > +++ b/kernel/trace/trace_events_filter.c > @@ -596,6 +596,12 @@ predicate_parse(const char *str, int nr_parens, int > nr_preds, > top--; /* #12 */ > } > } > + /* Only the inner loop can complete a non-empty expression. */ > + if (N) { > + ret = -EINVAL; > + parse_error(pe, FILT_ERR_INVALID_FILTER, ptr - str); > + goto out_free; > + } > out: > if (top != op_stack) { > /* Too many '(' */ > diff --git > a/tools/testing/selftests/ftrace/test.d/filter/event-filter-incomplete.tc > b/tools/testing/selftests/ftrace/test.d/filter/event-filter-incomplete.tc > new file mode 100644 > index 000000000000..cc6df762845f > --- /dev/null > +++ b/tools/testing/selftests/ftrace/test.d/filter/event-filter-incomplete.tc > @@ -0,0 +1,24 @@ > +#!/bin/sh > +# SPDX-License-Identifier: GPL-2.0 > +# description: event filter - reject incomplete logical expressions > +# requires: events/sched/sched_switch/filter > +# flags: instance > + > +filter=events/sched/sched_switch/filter > + > +for base in \ > + 'common_pid == 1' \ > + 'common_pid == 1 || common_pid == 2' \ > + 'common_pid == 1 && common_pid == 2' \ > + '!(common_pid == 1 || common_pid == 2)' > +do > + printf '%s' "$base" > "$filter" > + for tail in '&&' '||' '&& !' '|| !' '&& !! ' '|| !! '; do > + if printf '%s' "$base $tail" > "$filter" 2>/dev/null; then > + echo "Accepted incomplete filter: $base $tail" > + exit_fail > + fi > + done > +done > + > +echo 0 > "$filter" > > base-commit: fd179f8a05be3ccae366b9b96e176b51fbe54aab > -- Masami Hiramatsu (Google) <[email protected]>
