]> git.ipfire.org Git - thirdparty/kernel/stable.git/commit
bpf: Add range tracking for BPF_NEG
authorSong Liu <song@kernel.org>
Wed, 25 Jun 2025 16:40:24 +0000 (09:40 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 25 Jun 2025 22:12:17 +0000 (15:12 -0700)
commitaced132599b3c8884c050218d4c48eef203678f6
tree7ee732f1ea148b5b2edb252b46ece689a83df4e2
parentd69bafe6ee2b5eff6099fa26626ecc2963f0f363
bpf: Add range tracking for BPF_NEG

Add range tracking for instruction BPF_NEG. Without this logic, a trivial
program like the following will fail

    volatile bool found_value_b;
    SEC("lsm.s/socket_connect")
    int BPF_PROG(test_socket_connect)
    {
        if (!found_value_b)
                return -1;
        return 0;
    }

with verifier log:

"At program exit the register R0 has smin=0 smax=4294967295 should have
been in [-4095, 0]".

This is because range information is lost in BPF_NEG:

0: R1=ctx() R10=fp0
; if (!found_value_b) @ xxxx.c:24
0: (18) r1 = 0xffa00000011e7048       ; R1_w=map_value(...)
2: (71) r0 = *(u8 *)(r1 +0)           ; R0_w=scalar(smin32=0,smax=255)
3: (a4) w0 ^= 1                       ; R0_w=scalar(smin32=0,smax=255)
4: (84) w0 = -w0                      ; R0_w=scalar(range info lost)

Note that, the log above is manually modified to highlight relevant bits.

Fix this by maintaining proper range information with BPF_NEG, so that
the verifier will know:

4: (84) w0 = -w0                      ; R0_w=scalar(smin32=-255,smax=0)

Also updated selftests based on the expected behavior.

Signed-off-by: Song Liu <song@kernel.org>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20250625164025.3310203-2-song@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
include/linux/tnum.h
kernel/bpf/tnum.c
kernel/bpf/verifier.c
tools/testing/selftests/bpf/progs/verifier_bounds_deduction.c
tools/testing/selftests/bpf/progs/verifier_value_ptr_arith.c