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

selftests/bpf: Test epilogue patching when the main prog has multiple BPF_EXIT

This patch tests the epilogue patching when the main prog has
multiple BPF_EXIT. The verifier should have patched the 2nd (and
later) BPF_EXIT with a BPF_JA that goes back to the earlier
patched epilogue instructions.

Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Link: https://lore.kernel.org/r/20240829210833.388152-10-martin.lau@linux.dev
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Martin KaFai Lau and committed by
Alexei Starovoitov
cada0bdc 42fdbbde

+84
+2
tools/testing/selftests/bpf/prog_tests/pro_epilogue.c
··· 5 5 #include "pro_epilogue.skel.h" 6 6 #include "epilogue_tailcall.skel.h" 7 7 #include "pro_epilogue_goto_start.skel.h" 8 + #include "epilogue_exit.skel.h" 8 9 9 10 struct st_ops_args { 10 11 __u64 a; ··· 54 53 { 55 54 RUN_TESTS(pro_epilogue); 56 55 RUN_TESTS(pro_epilogue_goto_start); 56 + RUN_TESTS(epilogue_exit); 57 57 if (test__start_subtest("tailcall")) 58 58 test_tailcall(); 59 59 }
+82
tools/testing/selftests/bpf/progs/epilogue_exit.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024 Meta Platforms, Inc. and affiliates. */ 3 + 4 + #include <vmlinux.h> 5 + #include <bpf/bpf_tracing.h> 6 + #include "bpf_misc.h" 7 + #include "../bpf_testmod/bpf_testmod.h" 8 + #include "../bpf_testmod/bpf_testmod_kfunc.h" 9 + 10 + char _license[] SEC("license") = "GPL"; 11 + 12 + __success 13 + /* save __u64 *ctx to stack */ 14 + __xlated("0: *(u64 *)(r10 -8) = r1") 15 + /* main prog */ 16 + __xlated("1: r1 = *(u64 *)(r1 +0)") 17 + __xlated("2: r2 = *(u64 *)(r1 +0)") 18 + __xlated("3: r3 = 0") 19 + __xlated("4: r4 = 1") 20 + __xlated("5: if r2 == 0x0 goto pc+10") 21 + __xlated("6: r0 = 0") 22 + __xlated("7: *(u64 *)(r1 +0) = r3") 23 + /* epilogue */ 24 + __xlated("8: r1 = *(u64 *)(r10 -8)") 25 + __xlated("9: r1 = *(u64 *)(r1 +0)") 26 + __xlated("10: r6 = *(u64 *)(r1 +0)") 27 + __xlated("11: r6 += 10000") 28 + __xlated("12: *(u64 *)(r1 +0) = r6") 29 + __xlated("13: r0 = r6") 30 + __xlated("14: r0 *= 2") 31 + __xlated("15: exit") 32 + /* 2nd part of the main prog after the first exit */ 33 + __xlated("16: *(u64 *)(r1 +0) = r4") 34 + __xlated("17: r0 = 1") 35 + /* Clear the r1 to ensure it does not have 36 + * off-by-1 error and ensure it jumps back to the 37 + * beginning of epilogue which initializes 38 + * the r1 with the ctx ptr. 39 + */ 40 + __xlated("18: r1 = 0") 41 + __xlated("19: gotol pc-12") 42 + SEC("struct_ops/test_epilogue_exit") 43 + __naked int test_epilogue_exit(void) 44 + { 45 + asm volatile ( 46 + "r1 = *(u64 *)(r1 +0);" 47 + "r2 = *(u64 *)(r1 +0);" 48 + "r3 = 0;" 49 + "r4 = 1;" 50 + "if r2 == 0 goto +3;" 51 + "r0 = 0;" 52 + "*(u64 *)(r1 + 0) = r3;" 53 + "exit;" 54 + "*(u64 *)(r1 + 0) = r4;" 55 + "r0 = 1;" 56 + "r1 = 0;" 57 + "exit;" 58 + ::: __clobber_all); 59 + } 60 + 61 + SEC(".struct_ops.link") 62 + struct bpf_testmod_st_ops epilogue_exit = { 63 + .test_epilogue = (void *)test_epilogue_exit, 64 + }; 65 + 66 + SEC("syscall") 67 + __retval(20000) 68 + int syscall_epilogue_exit0(void *ctx) 69 + { 70 + struct st_ops_args args = { .a = 1 }; 71 + 72 + return bpf_kfunc_st_ops_test_epilogue(&args); 73 + } 74 + 75 + SEC("syscall") 76 + __retval(20002) 77 + int syscall_epilogue_exit1(void *ctx) 78 + { 79 + struct st_ops_args args = {}; 80 + 81 + return bpf_kfunc_st_ops_test_epilogue(&args); 82 + }