diff mbox series

[bpf-next,v2,09/11] selftests/bpf: Add dynptr var_off tests

Message ID 20230119021442.1465269-10-memxor@gmail.com (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series Dynptr fixes | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-31 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-PR success PR summary
netdev/tree_selection success Clearly marked for bpf-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 11 maintainers not CCed: linux-kselftest@vger.kernel.org kpsingh@kernel.org haoluo@google.com song@kernel.org yhs@fb.com martin.lau@linux.dev sdf@google.com john.fastabend@gmail.com shuah@kernel.org jolsa@kernel.org mykolal@fb.com
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch warning CHECK: Lines should not end with a '(' WARNING: quoted string split across lines
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-7 success Logs for llvm-toolchain
bpf/vmtest-bpf-next-VM_Test-8 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-37 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-38 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32 on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_progs_no_alu32_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-29 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for test_progs_parallel on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-32 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-33 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-34 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-35 success Logs for test_verifier on aarch64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-36 success Logs for test_verifier on s390x with gcc

Commit Message

Kumar Kartikeya Dwivedi Jan. 19, 2023, 2:14 a.m. UTC
Ensure that variable offset is handled correctly, and verifier takes
both fixed and variable part into account. Also ensures that only
constant var_off is allowed.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 .../testing/selftests/bpf/progs/dynptr_fail.c | 40 +++++++++++++++++++
 1 file changed, 40 insertions(+)

Comments

Joanne Koong Jan. 19, 2023, 10:49 p.m. UTC | #1
On Wed, Jan 18, 2023 at 6:15 PM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> Ensure that variable offset is handled correctly, and verifier takes
> both fixed and variable part into account. Also ensures that only
> constant var_off is allowed.
>
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---
>  .../testing/selftests/bpf/progs/dynptr_fail.c | 40 +++++++++++++++++++
>  1 file changed, 40 insertions(+)
>
> diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> index 023b3c36bc78..063d351f327a 100644
> --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
> +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> @@ -794,3 +794,43 @@ int dynptr_pruning_type_confusion(struct __sk_buff *ctx)
>         );
>         return 0;
>  }
> +
> +SEC("?tc")
> +__failure __msg("dynptr has to be at the constant offset") __log_level(2)
> +int dynptr_var_off_overwrite(struct __sk_buff *ctx)
> +{
> +       asm volatile (
> +               "r9 = 16;"
> +               "*(u32 *)(r10 - 4) = r9;"
> +               "r8 = *(u32 *)(r10 - 4);"
> +               "if r8 >= 0 goto vjmp1;"
> +               "r0 = 1;"
> +               "exit;"
> +       "vjmp1:"
> +               "if r8 <= 16 goto vjmp2;"
> +               "r0 = 1;"
> +               "exit;"
> +       "vjmp2:"
> +               "r8 &= 16;"
> +               "r1 = %[ringbuf] ll;"
> +               "r2 = 8;"
> +               "r3 = 0;"
> +               "r4 = r10;"
> +               "r4 += -32;"
> +               "r4 += r8;"
> +               "call %[bpf_ringbuf_reserve_dynptr];"
> +               "r9 = 0xeB9F;"
> +               "*(u64 *)(r10 - 16) = r9;"
> +               "r1 = r10;"
> +               "r1 += -32;"
> +               "r1 += r8;"
> +               "r2 = 0;"
> +               "call %[bpf_ringbuf_discard_dynptr];"
> +               :
> +               : __imm(bpf_ringbuf_reserve_dynptr),
> +                 __imm(bpf_ringbuf_discard_dynptr),
> +                 __imm_addr(ringbuf)
> +               : __clobber_all
> +       );
> +       return 0;
> +}

Thanks for adding these series of tests. From a readibility
perspective, are we able to simulate these tests in C instead of
assembly?
> --
> 2.39.1
>
Kumar Kartikeya Dwivedi Jan. 20, 2023, 1:59 a.m. UTC | #2
On Fri, Jan 20, 2023 at 04:19:31AM IST, Joanne Koong wrote:
> On Wed, Jan 18, 2023 at 6:15 PM Kumar Kartikeya Dwivedi
> <memxor@gmail.com> wrote:
> >
> > Ensure that variable offset is handled correctly, and verifier takes
> > both fixed and variable part into account. Also ensures that only
> > constant var_off is allowed.
> >
> > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> > ---
> >  .../testing/selftests/bpf/progs/dynptr_fail.c | 40 +++++++++++++++++++
> >  1 file changed, 40 insertions(+)
> >
> > diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > index 023b3c36bc78..063d351f327a 100644
> > --- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > +++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
> > @@ -794,3 +794,43 @@ int dynptr_pruning_type_confusion(struct __sk_buff *ctx)
> >         );
> >         return 0;
> >  }
> > +
> > +SEC("?tc")
> > +__failure __msg("dynptr has to be at the constant offset") __log_level(2)
> > +int dynptr_var_off_overwrite(struct __sk_buff *ctx)
> > +{
> > +       asm volatile (
> > +               "r9 = 16;"
> > +               "*(u32 *)(r10 - 4) = r9;"
> > +               "r8 = *(u32 *)(r10 - 4);"
> > +               "if r8 >= 0 goto vjmp1;"
> > +               "r0 = 1;"
> > +               "exit;"
> > +       "vjmp1:"
> > +               "if r8 <= 16 goto vjmp2;"
> > +               "r0 = 1;"
> > +               "exit;"
> > +       "vjmp2:"
> > +               "r8 &= 16;"
> > +               "r1 = %[ringbuf] ll;"
> > +               "r2 = 8;"
> > +               "r3 = 0;"
> > +               "r4 = r10;"
> > +               "r4 += -32;"
> > +               "r4 += r8;"
> > +               "call %[bpf_ringbuf_reserve_dynptr];"
> > +               "r9 = 0xeB9F;"
> > +               "*(u64 *)(r10 - 16) = r9;"
> > +               "r1 = r10;"
> > +               "r1 += -32;"
> > +               "r1 += r8;"
> > +               "r2 = 0;"
> > +               "call %[bpf_ringbuf_discard_dynptr];"
> > +               :
> > +               : __imm(bpf_ringbuf_reserve_dynptr),
> > +                 __imm(bpf_ringbuf_discard_dynptr),
> > +                 __imm_addr(ringbuf)
> > +               : __clobber_all
> > +       );
> > +       return 0;
> > +}
>
> Thanks for adding these series of tests. From a readibility
> perspective, are we able to simulate these tests in C instead of
> assembly?

It should be possible, but I went with assembly for two reasons:
- In one of the tests extra instructions are emitted at a specific place in the
  program to trigger add_new_state heuristic of the verifier. I was having
  trouble making this work when initially trying to trigger the bug in C.
- Preventing compiler changes from changing the desired BPF assembly that should
  be produced over time. I'm mostly worried about these changes happening
  silently and the test becoming useless over time without being able to detect
  so. Right now you can take these ASM tests and run them on an unpatched kernel
  and it will successfully load the program (on running crash it).

In the last patch I still added C tests as those shouldn't need assembly.
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/progs/dynptr_fail.c b/tools/testing/selftests/bpf/progs/dynptr_fail.c
index 023b3c36bc78..063d351f327a 100644
--- a/tools/testing/selftests/bpf/progs/dynptr_fail.c
+++ b/tools/testing/selftests/bpf/progs/dynptr_fail.c
@@ -794,3 +794,43 @@  int dynptr_pruning_type_confusion(struct __sk_buff *ctx)
 	);
 	return 0;
 }
+
+SEC("?tc")
+__failure __msg("dynptr has to be at the constant offset") __log_level(2)
+int dynptr_var_off_overwrite(struct __sk_buff *ctx)
+{
+	asm volatile (
+		"r9 = 16;"
+		"*(u32 *)(r10 - 4) = r9;"
+		"r8 = *(u32 *)(r10 - 4);"
+		"if r8 >= 0 goto vjmp1;"
+		"r0 = 1;"
+		"exit;"
+	"vjmp1:"
+		"if r8 <= 16 goto vjmp2;"
+		"r0 = 1;"
+		"exit;"
+	"vjmp2:"
+		"r8 &= 16;"
+		"r1 = %[ringbuf] ll;"
+		"r2 = 8;"
+		"r3 = 0;"
+		"r4 = r10;"
+		"r4 += -32;"
+		"r4 += r8;"
+		"call %[bpf_ringbuf_reserve_dynptr];"
+		"r9 = 0xeB9F;"
+		"*(u64 *)(r10 - 16) = r9;"
+		"r1 = r10;"
+		"r1 += -32;"
+		"r1 += r8;"
+		"r2 = 0;"
+		"call %[bpf_ringbuf_discard_dynptr];"
+		:
+		: __imm(bpf_ringbuf_reserve_dynptr),
+		  __imm(bpf_ringbuf_discard_dynptr),
+		  __imm_addr(ringbuf)
+		: __clobber_all
+	);
+	return 0;
+}