selftests/bpf: Test bpf_throw() in a prog with a private stack

'Private stack, exception in main prog' and 'Private stack, exception in
subprog' are fentry progs. The test loader does not attach them, and
BPF_PROG_TEST_RUN of a fentry prog does not call the prog. They are
loaded, but they never run.

Add three raw_tp progs. BPF_PROG_TEST_RUN runs them, and the default
exception callback returns the cookie of bpf_throw():
 - the main prog has a private stack and throws
 - the main prog has a private stack, its subprog throws
 - the main prog has no private stack, its subprog has one and throws

Without the fix of the x86-64 JIT the first two crash the kernel. The
third one passes with and without it: it makes sure that only the frame
of the main prog is taken into account.

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Link: https://patch.msgid.link/20261031050558.2410721-3-alexei.starovoitov@gmail.com
This commit is contained in:
Alexei Starovoitov 2026-10-31 05:05:58 +00:00
parent 91068ed2d3
commit 6cc0cf0a6f
No known key found for this signature in database

View File

@ -279,6 +279,105 @@ int private_stack_exception_sub_prog(void)
return 0;
}
/*
* Nothing attaches the two fentry progs above, so they are loaded, but never
* run. BPF_PROG_TEST_RUN does run a raw_tp prog. The default exception callback
* returns the cookie of bpf_throw().
*/
SEC("raw_tp")
__description("Private stack, run, exception in main prog")
__success __retval(1)
__arch_x86_64
__jited(" movq %rdi, -0x200(%r9)")
__jited(" movl $0x1, %edi")
__jited(" pushq %r9")
__jited("...")
__jited(" callq")
__naked void private_stack_run_exception_main_prog(void)
{
asm volatile (" \
r1 = 42; \
*(u64 *)(r10 - 512) = r1; \
r1 = 1; \
call %[bpf_throw]; \
r0 = 0; \
exit; \
" :
: __imm(bpf_throw)
: __clobber_all);
}
__used
__naked static void subprog_throw(void)
{
asm volatile (" \
r1 = 2; \
call %[bpf_throw]; \
r0 = 0; \
exit; \
" :
: __imm(bpf_throw)
: __clobber_all);
}
SEC("raw_tp")
__description("Private stack, run, exception in subprog")
__success __retval(2)
__arch_x86_64
__jited(" movq %rdi, -0x200(%r9)")
__jited(" pushq %r9")
__jited("...")
__jited(" callq")
__jited(" popq %r9")
__naked void private_stack_run_exception_sub_prog(void)
{
asm volatile (" \
r1 = 42; \
*(u64 *)(r10 - 512) = r1; \
call subprog_throw; \
r0 = 0; \
exit; \
" ::: __clobber_all);
}
__used
__naked static void private_stack_subprog_throw(void)
{
asm volatile (" \
r1 = 42; \
*(u64 *)(r10 - 512) = r1; \
r1 = 3; \
call %[bpf_throw]; \
r0 = 0; \
exit; \
" :
: __imm(bpf_throw)
: __clobber_all);
}
/* Only the frame of the main prog counts, and it has nothing pushed at the call */
SEC("raw_tp")
__description("Private stack, run, exception in subprog, no private stack in main prog")
__success __retval(3)
__arch_x86_64
__jited(" subq $0x8, %rsp")
__jited("...")
__jited("func #1")
__jited("...")
__jited(" movq %rdi, -0x200(%r9)")
__jited(" movl $0x3, %edi")
__jited(" pushq %r9")
__naked void no_private_stack_run_exception_sub_prog(void)
{
asm volatile (" \
r1 = 42; \
*(u64 *)(r10 - 8) = r1; \
call private_stack_subprog_throw; \
r0 = 0; \
exit; \
" ::: __clobber_all);
}
int glob;
__noinline static void subprog2(int *val)
{