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

selftests: bpf: test writable buffers in raw tps

This tests that:
* a BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE cannot be attached if it
uses either:
* a variable offset to the tracepoint buffer, or
* an offset beyond the size of the tracepoint buffer
* a tracer can modify the buffer provided when attached to a writable
tracepoint in bpf_prog_test_run

Signed-off-by: Matt Mullins <mmullins@fb.com>
Acked-by: Yonghong Song <yhs@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Matt Mullins and committed by
Alexei Starovoitov
e950e843 4635b0ae

+210
+50
include/trace/events/bpf_test_run.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #undef TRACE_SYSTEM 3 + #define TRACE_SYSTEM bpf_test_run 4 + 5 + #if !defined(_TRACE_BPF_TEST_RUN_H) || defined(TRACE_HEADER_MULTI_READ) 6 + #define _TRACE_BPF_TEST_RUN_H 7 + 8 + #include <linux/tracepoint.h> 9 + 10 + DECLARE_EVENT_CLASS(bpf_test_finish, 11 + 12 + TP_PROTO(int *err), 13 + 14 + TP_ARGS(err), 15 + 16 + TP_STRUCT__entry( 17 + __field(int, err) 18 + ), 19 + 20 + TP_fast_assign( 21 + __entry->err = *err; 22 + ), 23 + 24 + TP_printk("bpf_test_finish with err=%d", __entry->err) 25 + ); 26 + 27 + #ifdef DEFINE_EVENT_WRITABLE 28 + #undef BPF_TEST_RUN_DEFINE_EVENT 29 + #define BPF_TEST_RUN_DEFINE_EVENT(template, call, proto, args, size) \ 30 + DEFINE_EVENT_WRITABLE(template, call, PARAMS(proto), \ 31 + PARAMS(args), size) 32 + #else 33 + #undef BPF_TEST_RUN_DEFINE_EVENT 34 + #define BPF_TEST_RUN_DEFINE_EVENT(template, call, proto, args, size) \ 35 + DEFINE_EVENT(template, call, PARAMS(proto), PARAMS(args)) 36 + #endif 37 + 38 + BPF_TEST_RUN_DEFINE_EVENT(bpf_test_finish, bpf_test_finish, 39 + 40 + TP_PROTO(int *err), 41 + 42 + TP_ARGS(err), 43 + 44 + sizeof(int) 45 + ); 46 + 47 + #endif 48 + 49 + /* This part must be outside protection */ 50 + #include <trace/define_trace.h>
+4
net/bpf/test_run.c
··· 13 13 #include <net/sock.h> 14 14 #include <net/tcp.h> 15 15 16 + #define CREATE_TRACE_POINTS 17 + #include <trace/events/bpf_test_run.h> 18 + 16 19 static int bpf_test_run(struct bpf_prog *prog, void *ctx, u32 repeat, 17 20 u32 *retval, u32 *time) 18 21 { ··· 103 100 if (err != -ENOSPC) 104 101 err = 0; 105 102 out: 103 + trace_bpf_test_finish(&err); 106 104 return err; 107 105 } 108 106
+42
tools/testing/selftests/bpf/prog_tests/raw_tp_writable_reject_nbd_invalid.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <test_progs.h> 4 + #include <linux/nbd.h> 5 + 6 + void test_raw_tp_writable_reject_nbd_invalid(void) 7 + { 8 + __u32 duration = 0; 9 + char error[4096]; 10 + int bpf_fd = -1, tp_fd = -1; 11 + 12 + const struct bpf_insn program[] = { 13 + /* r6 is our tp buffer */ 14 + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), 15 + /* one byte beyond the end of the nbd_request struct */ 16 + BPF_LDX_MEM(BPF_B, BPF_REG_0, BPF_REG_6, 17 + sizeof(struct nbd_request)), 18 + BPF_EXIT_INSN(), 19 + }; 20 + 21 + struct bpf_load_program_attr load_attr = { 22 + .prog_type = BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, 23 + .license = "GPL v2", 24 + .insns = program, 25 + .insns_cnt = sizeof(program) / sizeof(struct bpf_insn), 26 + .log_level = 2, 27 + }; 28 + 29 + bpf_fd = bpf_load_program_xattr(&load_attr, error, sizeof(error)); 30 + if (CHECK(bpf_fd < 0, "bpf_raw_tracepoint_writable load", 31 + "failed: %d errno %d\n", bpf_fd, errno)) 32 + return; 33 + 34 + tp_fd = bpf_raw_tracepoint_open("nbd_send_request", bpf_fd); 35 + if (CHECK(tp_fd >= 0, "bpf_raw_tracepoint_writable open", 36 + "erroneously succeeded\n")) 37 + goto out_bpffd; 38 + 39 + close(tp_fd); 40 + out_bpffd: 41 + close(bpf_fd); 42 + }
+80
tools/testing/selftests/bpf/prog_tests/raw_tp_writable_test_run.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <test_progs.h> 4 + #include <linux/nbd.h> 5 + 6 + void test_raw_tp_writable_test_run(void) 7 + { 8 + __u32 duration = 0; 9 + char error[4096]; 10 + 11 + const struct bpf_insn trace_program[] = { 12 + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), 13 + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_6, 0), 14 + BPF_MOV64_IMM(BPF_REG_0, 42), 15 + BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_0, 0), 16 + BPF_EXIT_INSN(), 17 + }; 18 + 19 + struct bpf_load_program_attr load_attr = { 20 + .prog_type = BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, 21 + .license = "GPL v2", 22 + .insns = trace_program, 23 + .insns_cnt = sizeof(trace_program) / sizeof(struct bpf_insn), 24 + .log_level = 2, 25 + }; 26 + 27 + int bpf_fd = bpf_load_program_xattr(&load_attr, error, sizeof(error)); 28 + if (CHECK(bpf_fd < 0, "bpf_raw_tracepoint_writable loaded", 29 + "failed: %d errno %d\n", bpf_fd, errno)) 30 + return; 31 + 32 + const struct bpf_insn skb_program[] = { 33 + BPF_MOV64_IMM(BPF_REG_0, 0), 34 + BPF_EXIT_INSN(), 35 + }; 36 + 37 + struct bpf_load_program_attr skb_load_attr = { 38 + .prog_type = BPF_PROG_TYPE_SOCKET_FILTER, 39 + .license = "GPL v2", 40 + .insns = skb_program, 41 + .insns_cnt = sizeof(skb_program) / sizeof(struct bpf_insn), 42 + }; 43 + 44 + int filter_fd = 45 + bpf_load_program_xattr(&skb_load_attr, error, sizeof(error)); 46 + if (CHECK(filter_fd < 0, "test_program_loaded", "failed: %d errno %d\n", 47 + filter_fd, errno)) 48 + goto out_bpffd; 49 + 50 + int tp_fd = bpf_raw_tracepoint_open("bpf_test_finish", bpf_fd); 51 + if (CHECK(tp_fd < 0, "bpf_raw_tracepoint_writable opened", 52 + "failed: %d errno %d\n", tp_fd, errno)) 53 + goto out_filterfd; 54 + 55 + char test_skb[128] = { 56 + 0, 57 + }; 58 + 59 + __u32 prog_ret; 60 + int err = bpf_prog_test_run(filter_fd, 1, test_skb, sizeof(test_skb), 0, 61 + 0, &prog_ret, 0); 62 + CHECK(err != 42, "test_run", 63 + "tracepoint did not modify return value\n"); 64 + CHECK(prog_ret != 0, "test_run_ret", 65 + "socket_filter did not return 0\n"); 66 + 67 + close(tp_fd); 68 + 69 + err = bpf_prog_test_run(filter_fd, 1, test_skb, sizeof(test_skb), 0, 0, 70 + &prog_ret, 0); 71 + CHECK(err != 0, "test_run_notrace", 72 + "test_run failed with %d errno %d\n", err, errno); 73 + CHECK(prog_ret != 0, "test_run_ret_notrace", 74 + "socket_filter did not return 0\n"); 75 + 76 + out_filterfd: 77 + close(filter_fd); 78 + out_bpffd: 79 + close(bpf_fd); 80 + }
+34
tools/testing/selftests/bpf/verifier/raw_tp_writable.c
··· 1 + { 2 + "raw_tracepoint_writable: reject variable offset", 3 + .insns = { 4 + /* r6 is our tp buffer */ 5 + BPF_LDX_MEM(BPF_DW, BPF_REG_6, BPF_REG_1, 0), 6 + 7 + BPF_LD_MAP_FD(BPF_REG_1, 0), 8 + /* move the key (== 0) to r10-8 */ 9 + BPF_MOV32_IMM(BPF_REG_0, 0), 10 + BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), 11 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8), 12 + BPF_STX_MEM(BPF_DW, BPF_REG_2, BPF_REG_0, 0), 13 + /* lookup in the map */ 14 + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, 15 + BPF_FUNC_map_lookup_elem), 16 + 17 + /* exit clean if null */ 18 + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), 19 + BPF_EXIT_INSN(), 20 + 21 + /* shift the buffer pointer to a variable location */ 22 + BPF_LDX_MEM(BPF_W, BPF_REG_0, BPF_REG_0, 0), 23 + BPF_ALU64_REG(BPF_ADD, BPF_REG_6, BPF_REG_0), 24 + /* clobber whatever's there */ 25 + BPF_MOV64_IMM(BPF_REG_7, 4242), 26 + BPF_STX_MEM(BPF_DW, BPF_REG_6, BPF_REG_7, 0), 27 + 28 + BPF_MOV64_IMM(BPF_REG_0, 0), 29 + BPF_EXIT_INSN(), 30 + }, 31 + .fixup_map_hash_8b = { 1, }, 32 + .prog_type = BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, 33 + .errstr = "R6 invalid variable buffer offset: off=0, var_off=(0x0; 0xffffffff)", 34 + },