tracing: Reject incomplete event filter expressions

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.

Fixes: 80765597bc ("tracing: Rewrite filter logic to be simpler and faster")
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20261023174620.91969-1-kylebot@openai.com
Assisted-by: Codex:gpt-6-astra
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Tested-by: JongHyuk Kim(MalHyuk) <malhyuk97@gmail.com>
Signed-off-by: Kyle Zeng <kylebot@openai.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
Kyle Zeng 2026-10-23 10:46:20 -07:00 committed by Steven Rostedt
parent c0c7c3f9d2
commit 1fdc4164e4
2 changed files with 30 additions and 0 deletions

View File

@ -598,6 +598,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 '(' */

View File

@ -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"