bpf: Improve handling of pattern '<const> <cond_op> <non_const>' in verifier
authorYonghong Song <yhs@fb.com>
Thu, 6 Apr 2023 16:45:05 +0000 (09:45 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Thu, 6 Apr 2023 22:26:08 +0000 (15:26 -0700)
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>
kernel/bpf/verifier.c
tools/testing/selftests/bpf/progs/verifier_bounds_mix_sign_unsign.c

index 5c6b90e..3660b57 100644 (file)
@@ -13356,6 +13356,18 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
                                       src_reg->var_off.value,
                                       opcode,
                                       is_jmp32);
+       } else if (dst_reg->type == SCALAR_VALUE &&
+                  is_jmp32 && tnum_is_const(tnum_subreg(dst_reg->var_off))) {
+               pred = is_branch_taken(src_reg,
+                                      tnum_subreg(dst_reg->var_off).value,
+                                      flip_opcode(opcode),
+                                      is_jmp32);
+       } else if (dst_reg->type == SCALAR_VALUE &&
+                  !is_jmp32 && tnum_is_const(dst_reg->var_off)) {
+               pred = is_branch_taken(src_reg,
+                                      dst_reg->var_off.value,
+                                      flip_opcode(opcode),
+                                      is_jmp32);
        } else if (reg_is_pkt_pointer_any(dst_reg) &&
                   reg_is_pkt_pointer_any(src_reg) &&
                   !is_jmp32) {
index 91a6635..4f40144 100644 (file)
@@ -354,7 +354,7 @@ __naked void signed_and_unsigned_variant_10(void)
        call %[bpf_map_lookup_elem];                    \
        if r0 == 0 goto l0_%=;                          \
        r1 = *(u64*)(r10 - 16);                         \
-       r2 = 0;                                         \
+       r2 = -1;                                                \
        if r2 > r1 goto l1_%=;                          \
        r0 = 0;                                         \
        exit;                                           \