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

bpf: Improve handling of pattern '<const> <cond_op> <non_const>' in verifier

Currently, the verifier does not handle '<const> <cond_op> <non_const>' well.
For example,
...
10: (79) r1 = *(u64 *)(r10 -16) ; R1_w=scalar() R10=fp0
11: (b7) r2 = 0 ; R2_w=0
12: (2d) if r2 > r1 goto pc+2
13: (b7) r0 = 0
14: (95) exit
15: (65) if r1 s> 0x1 goto pc+3
16: (0f) r0 += r1
...
At insn 12, verifier decides both true and false branch are possible, but
actually only false branch is possible.

Currently, the verifier already supports patterns '<non_const> <cond_op> <const>.
Add support for patterns '<const> <cond_op> <non_const>' in a similar way.

Also fix selftest 'verifier_bounds_mix_sign_unsign/bounds checks mixing signed and unsigned, variant 10'
due to this change.

Signed-off-by: Yonghong Song <yhs@fb.com>
Acked-by: Dave Marchevsky <davemarchevsky@fb.com>
Acked-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20230406164505.1046801-1-yhs@fb.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Yonghong Song and committed by
Alexei Starovoitov
953d9f5b aec08d67

+13 -1
+12
kernel/bpf/verifier.c
··· 13356 13356 src_reg->var_off.value, 13357 13357 opcode, 13358 13358 is_jmp32); 13359 + } else if (dst_reg->type == SCALAR_VALUE && 13360 + is_jmp32 && tnum_is_const(tnum_subreg(dst_reg->var_off))) { 13361 + pred = is_branch_taken(src_reg, 13362 + tnum_subreg(dst_reg->var_off).value, 13363 + flip_opcode(opcode), 13364 + is_jmp32); 13365 + } else if (dst_reg->type == SCALAR_VALUE && 13366 + !is_jmp32 && tnum_is_const(dst_reg->var_off)) { 13367 + pred = is_branch_taken(src_reg, 13368 + dst_reg->var_off.value, 13369 + flip_opcode(opcode), 13370 + is_jmp32); 13359 13371 } else if (reg_is_pkt_pointer_any(dst_reg) && 13360 13372 reg_is_pkt_pointer_any(src_reg) && 13361 13373 !is_jmp32) {
+1 -1
tools/testing/selftests/bpf/progs/verifier_bounds_mix_sign_unsign.c
··· 354 354 call %[bpf_map_lookup_elem]; \ 355 355 if r0 == 0 goto l0_%=; \ 356 356 r1 = *(u64*)(r10 - 16); \ 357 - r2 = 0; \ 357 + r2 = -1; \ 358 358 if r2 > r1 goto l1_%=; \ 359 359 r0 = 0; \ 360 360 exit; \