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

selftests/bpf: Add verifier test exercising jit PROBE_MEM logic

This patch adds a test exercising logic that was fixed / improved in
the previous patch in the series, as well as general sanity checking for
jit's PROBE_MEM logic which should've been unaffected by the previous
patch.

The added verifier test does the following:

* Acquire a referenced kptr to struct prog_test_ref_kfunc using
existing net/bpf/test_run.c kfunc
* Helper returns ptr to a specific prog_test_ref_kfunc whose first
two fields - both ints - have been prepopulated w/ vals 42 and
108, respectively
* kptr_xchg the acquired ptr into an arraymap
* Do a direct map_value load of the just-added ptr
* Goal of all this setup is to get an unreferenced kptr pointing to
struct with ints of known value, which is the result of this step
* Using unreferenced kptr obtained in previous step, do loads of
prog_test_ref_kfunc.a (offset 0) and .b (offset 4)
* Then incr the kptr by 8 and load prog_test_ref_kfunc.a again (this
time at offset -8)
* Add all the loaded ints together and return

Before the PROBE_MEM fixes in previous patch, the loads at offset 0 and
4 would succeed, while the load at offset -8 would incorrectly fail
runtime check emitted by the JIT and 0 out dst reg as a result. This
confirmed by retval of 150 for this test before previous patch - since
second .a read is 0'd out - and a retval of 192 with the fixed logic.

The test exercises the two optimizations to fixed logic added in last
patch as well:

* First load, with insn "r8 = *(u32 *)(r9 + 0)" exercises "insn->off
is 0, no need to add / sub from src_reg" optimization
* Third load, with insn "r9 = *(u32 *)(r9 - 8)" exercises "src_reg ==
dst_reg, no need to restore src_reg after load" optimization

Signed-off-by: Dave Marchevsky <davemarchevsky@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20221216214319.3408356-2-davemarchevsky@fb.com

authored by

Dave Marchevsky and committed by
Daniel Borkmann
59fe41b5 90156f4b

+89
+28
tools/testing/selftests/bpf/prog_tests/jit_probe_mem.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 + #include <test_progs.h> 4 + #include <network_helpers.h> 5 + 6 + #include "jit_probe_mem.skel.h" 7 + 8 + void test_jit_probe_mem(void) 9 + { 10 + LIBBPF_OPTS(bpf_test_run_opts, opts, 11 + .data_in = &pkt_v4, 12 + .data_size_in = sizeof(pkt_v4), 13 + .repeat = 1, 14 + ); 15 + struct jit_probe_mem *skel; 16 + int ret; 17 + 18 + skel = jit_probe_mem__open_and_load(); 19 + if (!ASSERT_OK_PTR(skel, "jit_probe_mem__open_and_load")) 20 + return; 21 + 22 + ret = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.test_jit_probe_mem), &opts); 23 + ASSERT_OK(ret, "jit_probe_mem ret"); 24 + ASSERT_OK(opts.retval, "jit_probe_mem opts.retval"); 25 + ASSERT_EQ(skel->data->total_sum, 192, "jit_probe_mem total_sum"); 26 + 27 + jit_probe_mem__destroy(skel); 28 + }
+61
tools/testing/selftests/bpf/progs/jit_probe_mem.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 + #include <vmlinux.h> 4 + #include <bpf/bpf_tracing.h> 5 + #include <bpf/bpf_helpers.h> 6 + 7 + static struct prog_test_ref_kfunc __kptr_ref *v; 8 + long total_sum = -1; 9 + 10 + extern struct prog_test_ref_kfunc *bpf_kfunc_call_test_acquire(unsigned long *sp) __ksym; 11 + extern void bpf_kfunc_call_test_release(struct prog_test_ref_kfunc *p) __ksym; 12 + 13 + SEC("tc") 14 + int test_jit_probe_mem(struct __sk_buff *ctx) 15 + { 16 + struct prog_test_ref_kfunc *p; 17 + unsigned long zero = 0, sum; 18 + 19 + p = bpf_kfunc_call_test_acquire(&zero); 20 + if (!p) 21 + return 1; 22 + 23 + p = bpf_kptr_xchg(&v, p); 24 + if (p) 25 + goto release_out; 26 + 27 + /* Direct map value access of kptr, should be PTR_UNTRUSTED */ 28 + p = v; 29 + if (!p) 30 + return 1; 31 + 32 + asm volatile ( 33 + "r9 = %[p];" 34 + "%[sum] = 0;" 35 + 36 + /* r8 = p->a */ 37 + "r8 = *(u32 *)(r9 + 0);" 38 + "%[sum] += r8;" 39 + 40 + /* r8 = p->b */ 41 + "r8 = *(u32 *)(r9 + 4);" 42 + "%[sum] += r8;" 43 + 44 + "r9 += 8;" 45 + /* r9 = p->a */ 46 + "r9 = *(u32 *)(r9 - 8);" 47 + "%[sum] += r9;" 48 + 49 + : [sum] "=r"(sum) 50 + : [p] "r"(p) 51 + : "r8", "r9" 52 + ); 53 + 54 + total_sum = sum; 55 + return 0; 56 + release_out: 57 + bpf_kfunc_call_test_release(p); 58 + return 1; 59 + } 60 + 61 + char _license[] SEC("license") = "GPL";