This patch adds tests for the previous patch, checking the tracking of the maximum stack size and checking that accesses to uninit stack memory are allowed. They are a separate patch for review purposes; whoever merges them can consider squashing. Signed-off-by: Andrei Matei <andreimatei1@xxxxxxxxx> --- tools/testing/selftests/bpf/test_verifier.c | 24 ++++++++++++ tools/testing/selftests/bpf/verifier/stack.c | 40 ++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 tools/testing/selftests/bpf/verifier/stack.c diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 98107e0452d3..a62610585ee4 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -135,6 +135,10 @@ struct bpf_test { const char *errstr; const char *errstr_unpriv; uint32_t insn_processed; + /* Expected maximum stack depth for the main subprogram. Not checked if 0. + * Only checked if the program is accepted. + */ + uint16_t max_stack_depth; int prog_len; enum { UNDEF, @@ -1703,6 +1707,26 @@ static void do_test_single(struct bpf_test *test, bool unpriv, } } + /* Check the stack size if the test configured an expecation and the program + * was loaded successfully. + */ + if (test->max_stack_depth && fd_prog >= 0) { + uint32_t max_stack; + char *s; + + s = strstr(bpf_vlog, "stack depth "); + if (s == NULL) { + printf("FAIL\nstack depth result not found in verifier output\n"); + goto fail_log; + } + max_stack = atoi(s + 12); + if (test->max_stack_depth != max_stack) { + printf("FAIL\nUnexpected max stack %u vs %u\n", + max_stack, test->max_stack_depth); + goto fail_log; + } + } + if (verbose) printf(", verifier log:\n%s", bpf_vlog); diff --git a/tools/testing/selftests/bpf/verifier/stack.c b/tools/testing/selftests/bpf/verifier/stack.c new file mode 100644 index 000000000000..ac571783c05e --- /dev/null +++ b/tools/testing/selftests/bpf/verifier/stack.c @@ -0,0 +1,40 @@ +{ + /* Check that reading unitialized stack memory is allowed only in privileged + * mode. Also check that such reads maintain the max stack depth. + */ + "read uninit stack", + .insns = { + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_10, -504), + /* exit(0); */ + BPF_MOV32_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .result_unpriv = REJECT, + .errstr_unpriv = "invalid read from stack", + .max_stack_depth = 504, +}, +{ + /* Check that indirect accesses to stack maintain the max stack depth. */ + "read (indirect) uninit stack", + .insns = { + /* We'll use probe_read_user as an arbitrary helper that can access the + * stack. We're going to read into *(fp-104). + */ + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -104), + BPF_MOV32_IMM(BPF_REG_2, 8), + /* read from a random address */ + BPF_MOV32_IMM(BPF_REG_3, 0x4242), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_probe_read_user), + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), + BPF_EXIT_INSN(), + /* exit(0); */ + BPF_MOV32_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + .result_unpriv = REJECT, + .errstr_unpriv = "", + .max_stack_depth = 104, +}, \ No newline at end of file -- 2.40.1