Message ID | 20231219134800.1550388-5-menglong8.dong@gmail.com |
---|---|
State | Accepted |
Commit | 463ea64eb008b7abb63245ed69446b404bf042b1 |
Headers | show |
Series | bpf: support to track BPF_JNE | expand |
On Tue, Dec 19, 2023 at 5:51 AM Menglong Dong <menglong8.dong@gmail.com> wrote: > > Add testcase for the logic that the verifier tracks the BPF_JNE for regs. > The assembly function "reg_not_equal_const()" and "reg_equal_const" that > we add is exactly converted from the following case: > > u32 a = bpf_get_prandom_u32(); > u64 b = 0; > > a %= 8; > /* the "a > 0" here will be optimized to "a != 0" */ > if (a > 0) { > /* now the range of a should be [1, 7] */ > bpf_skb_store_bytes(skb, 0, &b, a, 0); > } > > Signed-off-by: Menglong Dong <menglong8.dong@gmail.com> > --- > v5: > - add some comments to the function that we add > - add reg_not_equal_const() > --- > .../selftests/bpf/progs/verifier_bounds.c | 62 +++++++++++++++++++ > 1 file changed, 62 insertions(+) > LGTM Acked-by: Andrii Nakryiko <andrii@kernel.org> > diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c > index ec430b71730b..960998f16306 100644 > --- a/tools/testing/selftests/bpf/progs/verifier_bounds.c > +++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c > @@ -1075,4 +1075,66 @@ l0_%=: r0 = 0; \ > : __clobber_all); > } > > +SEC("tc") > +__description("bounds check with JMP_NE for reg edge") > +__success __retval(0) > +__naked void reg_not_equal_const(void) > +{ > + asm volatile (" \ > + r6 = r1; \ > + r1 = 0; \ > + *(u64*)(r10 - 8) = r1; \ > + call %[bpf_get_prandom_u32]; \ > + r4 = r0; \ > + r4 &= 7; \ > + if r4 != 0 goto l0_%=; \ > + r0 = 0; \ > + exit; \ > +l0_%=: r1 = r6; \ > + r2 = 0; \ > + r3 = r10; \ > + r3 += -8; \ > + r5 = 0; \ > + /* The 4th argument of bpf_skb_store_bytes is defined as \ > + * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \ > + * is providing us this exclusion of zero from initial \ > + * [0, 7] range. \ > + */ \ > + call %[bpf_skb_store_bytes]; \ > + r0 = 0; \ > + exit; \ > +" : > + : __imm(bpf_get_prandom_u32), > + __imm(bpf_skb_store_bytes) > + : __clobber_all); > +} > + > +SEC("tc") > +__description("bounds check with JMP_EQ for reg edge") > +__success __retval(0) > +__naked void reg_equal_const(void) > +{ > + asm volatile (" \ > + r6 = r1; \ > + r1 = 0; \ > + *(u64*)(r10 - 8) = r1; \ > + call %[bpf_get_prandom_u32]; \ > + r4 = r0; \ > + r4 &= 7; \ > + if r4 == 0 goto l0_%=; \ > + r1 = r6; \ > + r2 = 0; \ > + r3 = r10; \ > + r3 += -8; \ > + r5 = 0; \ > + /* Just the same as what we do in reg_not_equal_const() */ \ > + call %[bpf_skb_store_bytes]; \ > +l0_%=: r0 = 0; \ > + exit; \ > +" : > + : __imm(bpf_get_prandom_u32), > + __imm(bpf_skb_store_bytes) > + : __clobber_all); > +} > + > char _license[] SEC("license") = "GPL"; > -- > 2.39.2 >
diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c index ec430b71730b..960998f16306 100644 --- a/tools/testing/selftests/bpf/progs/verifier_bounds.c +++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c @@ -1075,4 +1075,66 @@ l0_%=: r0 = 0; \ : __clobber_all); } +SEC("tc") +__description("bounds check with JMP_NE for reg edge") +__success __retval(0) +__naked void reg_not_equal_const(void) +{ + asm volatile (" \ + r6 = r1; \ + r1 = 0; \ + *(u64*)(r10 - 8) = r1; \ + call %[bpf_get_prandom_u32]; \ + r4 = r0; \ + r4 &= 7; \ + if r4 != 0 goto l0_%=; \ + r0 = 0; \ + exit; \ +l0_%=: r1 = r6; \ + r2 = 0; \ + r3 = r10; \ + r3 += -8; \ + r5 = 0; \ + /* The 4th argument of bpf_skb_store_bytes is defined as \ + * ARG_CONST_SIZE, so 0 is not allowed. The 'r4 != 0' \ + * is providing us this exclusion of zero from initial \ + * [0, 7] range. \ + */ \ + call %[bpf_skb_store_bytes]; \ + r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32), + __imm(bpf_skb_store_bytes) + : __clobber_all); +} + +SEC("tc") +__description("bounds check with JMP_EQ for reg edge") +__success __retval(0) +__naked void reg_equal_const(void) +{ + asm volatile (" \ + r6 = r1; \ + r1 = 0; \ + *(u64*)(r10 - 8) = r1; \ + call %[bpf_get_prandom_u32]; \ + r4 = r0; \ + r4 &= 7; \ + if r4 == 0 goto l0_%=; \ + r1 = r6; \ + r2 = 0; \ + r3 = r10; \ + r3 += -8; \ + r5 = 0; \ + /* Just the same as what we do in reg_not_equal_const() */ \ + call %[bpf_skb_store_bytes]; \ +l0_%=: r0 = 0; \ + exit; \ +" : + : __imm(bpf_get_prandom_u32), + __imm(bpf_skb_store_bytes) + : __clobber_all); +} + char _license[] SEC("license") = "GPL";
Add testcase for the logic that the verifier tracks the BPF_JNE for regs. The assembly function "reg_not_equal_const()" and "reg_equal_const" that we add is exactly converted from the following case: u32 a = bpf_get_prandom_u32(); u64 b = 0; a %= 8; /* the "a > 0" here will be optimized to "a != 0" */ if (a > 0) { /* now the range of a should be [1, 7] */ bpf_skb_store_bytes(skb, 0, &b, a, 0); } Signed-off-by: Menglong Dong <menglong8.dong@gmail.com> --- v5: - add some comments to the function that we add - add reg_not_equal_const() --- .../selftests/bpf/progs/verifier_bounds.c | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+)