diff options
author | Eduard Zingerman <eddyz87@gmail.com> | 2024-01-08 22:51:56 +0200 |
---|---|---|
committer | Alexei Starovoitov <ast@kernel.org> | 2024-01-23 14:40:22 -0800 |
commit | d5b892fd607abec2a1e49b6a2afc278c329a0ee2 (patch) | |
tree | 50975743c8d1ad2caf70a4487f7f37f276dd71e8 /kernel/bpf/verifier.c | |
parent | 242d18514149d86b431b6f5db5a33579ea79ebad (diff) | |
download | linux-d5b892fd607abec2a1e49b6a2afc278c329a0ee2.tar.gz linux-d5b892fd607abec2a1e49b6a2afc278c329a0ee2.tar.bz2 linux-d5b892fd607abec2a1e49b6a2afc278c329a0ee2.zip |
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>
Diffstat (limited to 'kernel/bpf/verifier.c')
-rw-r--r-- | kernel/bpf/verifier.c | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 27ad463b3bdd..7ae4fa0a2c0c 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -17027,7 +17027,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx) } /* attempt to detect infinite loop to avoid unnecessary doomed work */ if (states_maybe_looping(&sl->state, cur) && - states_equal(env, &sl->state, cur, false) && + states_equal(env, &sl->state, cur, true) && !iter_active_depths_differ(&sl->state, cur) && sl->state.callback_unroll_depth == cur->callback_unroll_depth) { verbose_linfo(env, insn_idx, "; "); |