Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpf: make infinite loop detection in is_state_visited() exact

Current infinite loops detection mechanism is speculative:
- first, states_maybe_looping() check is done which simply does memcmp
for R1-R10 in current frame;
- second, states_equal(..., exact=false) is called. With exact=false
states_equal() would compare scalars for equality only if in old
state scalar has precision mark.

Such logic might be problematic if compiler makes some unlucky stack
spill/fill decisions. An artificial example of a false positive looks
as follows:

r0 = ... unknown scalar ...
r0 &= 0xff;
*(u64 *)(r10 - 8) = r0;
r0 = 0;
loop:
r0 = *(u64 *)(r10 - 8);
if r0 > 10 goto exit_;
r0 += 1;
*(u64 *)(r10 - 8) = r0;
r0 = 0;
goto loop;

This commit updates call to states_equal to use exact=true, forcing
all scalar comparisons to be exact.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20240108205209.838365-3-maxtram95@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Eduard Zingerman and committed by
Alexei Starovoitov
d5b892fd 242d1851

+1 -1
+1 -1
kernel/bpf/verifier.c
··· 17027 17027 } 17028 17028 /* attempt to detect infinite loop to avoid unnecessary doomed work */ 17029 17029 if (states_maybe_looping(&sl->state, cur) && 17030 - states_equal(env, &sl->state, cur, false) && 17030 + states_equal(env, &sl->state, cur, true) && 17031 17031 !iter_active_depths_differ(&sl->state, cur) && 17032 17032 sl->state.callback_unroll_depth == cur->callback_unroll_depth) { 17033 17033 verbose_linfo(env, insn_idx, "; ");