Re: [PATCH v3 bpf-next 1/2] bpf: Relax precision marking in open coded iters and may_goto loop.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2024-05-28 at 18:08 -0700, Eduard Zingerman wrote:

[...]

> > Because your guess at the reason for the verifier reject is not correct.
> > It's signed stuff that is causing issues.
> > s/int i/__u32 i/
> > and this test is passing the verifier with just 143 insn processed.
> 
> I'm reading through verifier log, will get back shortly.

Ok, so it is a bit more subtle than I thought.
Comparing verification log for master and v3 here is the state in
which they diverge and v3 rejects the program:

    from 14 to 15: R0=rdonly_mem(id=6,ref_obj_id=1,sz=4) R6=scalar(id=5) R7=2
                   R10=fp0 fp-8=iter_num(ref_id=1,state=active,depth=3) refs=1
    15: R0=rdonly_mem(id=6,ref_obj_id=1,sz=4) R6=scalar(id=5)
        R7=2 R10=fp0 fp-8=iter_num(ref_id=1,state=active,depth=3) refs=1
    15: (55) if r0 != 0x0 goto pc+5       ; R0=rdonly_mem(id=6,ref_obj_id=1,sz=4) refs=1
    ; if (i < 5) @ verifier_loops1.c:298
0-> 21: (65) if r7 s> 0x4 goto pc-10      ; R7=2 refs=1
    21: refs=1
    ; sum += arr[i++]; @ verifier_loops1.c:299
1-> 22: (bf) r1 = r7                      ; R1_w=scalar(id=7,smax=4) R7=scalar(id=7,smax=4) refs=1
2-> 23: (67) r1 <<= 3                     ; R1_w=scalar(smax=0x7ffffffffffffff8,
                                                        umax=0xfffffffffffffff8,
                                                        smax32=0x7ffffff8,
                                                        umax32=0xfffffff8,
                                                        var_off=(0x0; 0xfffffffffffffff8)) refs=1
    24: (18) r2 = 0xffffc900000f6000      ; R2_w=map_value(map=verifier.bss,ks=4,vs=80) refs=1
    26: (0f) r2 += r1
    mark_precise: frame0: last_idx 26 first_idx 21 subseq_idx -1 
    ...
    math between map_value pointer and register with unbounded min value is not allowed

At point (0) the r7 is tracked as 2, at point (1) it is widened by the
following code in the falltrhough branch processing:

+		if (ignore_pred) {
+			if (opcode != BPF_JEQ && opcode != BPF_JNE) {
+				widen_reg(dst_reg);
+				if (has_src_reg)
+					widen_reg(src_reg);
+			}
+			widen_reg(other_dst_reg);
+			if (has_src_reg)
+				widen_reg(other_src_reg);
+		} else {

Here src_reg is a fake register set to 4,
because comparison instruction is BPF_K it does not get widened.
So, reg_set_min_max() produces range [-SMIN,+4] for R7.
And at (2) all goes south because of the "<<" logic.
Switch to unsigned values helps because umax range is computed
instead of smax at point (1).

However, below is an example where if comparison is BPF_X.
Note that I obfuscated constant 5 as a volatile variable.
And here is what happens when verifier rejects the program:

    from 16 to 17: R0=rdonly_mem(id=6,ref_obj_id=1,sz=4) R6=scalar(id=5)
                   R7=2 R10=fp0 fp-8=5 fp-16=iter_num(ref_id=1,state=active,depth=3) refs=1
    17: R0=rdonly_mem(id=6,ref_obj_id=1,sz=4) R6=scalar(id=5)
        R7=2 R10=fp0 fp-8=5 fp-16=iter_num(ref_id=1,state=active,depth=3) refs=1
    17: (55) if r0 != 0x0 goto pc+5       ; R0=rdonly_mem(id=6,ref_obj_id=1,sz=4) refs=1
    ; if (i < five) @ verifier_loops1.c:299
    23: (79) r1 = *(u64 *)(r10 -8)        ; R1=5 R10=fp0 fp-8=5 refs=1
0-> 24: (3d) if r7 >= r1 goto pc-11       ; R1=5 R7=2 refs=1
    24: refs=1
    ; sum += arr[i++]; @ verifier_loops1.c:300
1-> 25: (bf) r1 = r7                      ; R1_w=scalar(id=7,umax=0xfffffffffffffffe)
                                            R7=scalar(id=7,umax=0xfffffffffffffffe) refs=1
    26: (67) r1 <<= 3                     ; R1_w=scalar(smax=0x7ffffffffffffff8,umax=0xfffffffffffffff8,
                                                        smax32=0x7ffffff8,umax32=0xfffffff8,
                                                        var_off=(0x0; 0xfffffffffffffff8)) refs=1
    27: (18) r2 = 0xffffc90000112000      ; R2_w=map_value(map=verifier.bss,ks=4,vs=80) refs=1
    29: (0f) r2 += r1

Note R7 has exact value 2 at point (0) and is widened to
umax=0xfffffffffffffffe at point (1).
Widening happens at the same point as before, but this time src_reg is
widened as well, so there is no upper bound for r7 anymore.

---

diff --git a/tools/testing/selftests/bpf/progs/verifier_loops1.c b/tools/testing/selftests/bpf/progs/verifier_loops1.c
index e07b43b78fd2..0249fb63f18b 100644
--- a/tools/testing/selftests/bpf/progs/verifier_loops1.c
+++ b/tools/testing/selftests/bpf/progs/verifier_loops1.c
@@ -283,4 +283,24 @@ exit_%=:                                           \
        : __clobber_all);
 }
 
+unsigned long arr[10];
+
+SEC("socket")
+__success __flag(BPF_F_TEST_STATE_FREQ)
+int simple_loop(const void *ctx)
+{
+      volatile unsigned long five = 5;
+      unsigned long sum = 0, i = 0;
+      struct bpf_iter_num it;
+      int *v;
+
+      bpf_iter_num_new(&it, 0, 10);
+      while ((v = bpf_iter_num_next(&it))) {
+              if (i < five)
+                      sum += arr[i++];
+      }
+      bpf_iter_num_destroy(&it);
+      return sum;
+}
+





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux