mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
selftests/bpf: Cover __uninit kfunc output argument slots
Keep coverage for per-slot output tracking separate from the immediate single-output regression tests. Check that both constant-size outputs are initialized, and that a variable-size output does not disable initialization of an independent constant-size output. Also exercise an output following a by-value parameter that occupies two argument slots, and an output pointer passed on the stack. Run each case with normal capabilities and with CAP_BPF and CAP_NET_ADMIN only. Leave the stack-passed output uninitialized so its reduced-capability case fails if the verifier treats it as an ordinary input buffer. Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://patch.msgid.link/20260921023843.411943-8-memxor@gmail.com
This commit is contained in:
parent
bca730ba6d
commit
89835699ef
|
|
@ -57,6 +57,7 @@
|
|||
#include "verifier_jit_convergence.skel.h"
|
||||
#include "verifier_kfunc_packet_access.skel.h"
|
||||
#include "verifier_kfunc_uninit.skel.h"
|
||||
#include "verifier_kfunc_uninit_multi.skel.h"
|
||||
#include "verifier_ld_ind.skel.h"
|
||||
#include "verifier_ldsx.skel.h"
|
||||
#include "verifier_leak_ptr.skel.h"
|
||||
|
|
@ -225,6 +226,7 @@ void test_verifier_jeq_infer_not_null(void) { RUN(verifier_jeq_infer_not_null)
|
|||
void test_verifier_jit_convergence(void) { RUN(verifier_jit_convergence); }
|
||||
void test_verifier_kfunc_packet_access(void) { RUN_TESTS(verifier_kfunc_packet_access); }
|
||||
void test_verifier_kfunc_uninit(void) { RUN_TESTS(verifier_kfunc_uninit); }
|
||||
void test_verifier_kfunc_uninit_multi(void) { RUN_TESTS(verifier_kfunc_uninit_multi); }
|
||||
void test_verifier_load_acquire(void) { RUN(verifier_load_acquire); }
|
||||
void test_verifier_ld_ind(void) { RUN(verifier_ld_ind); }
|
||||
void test_verifier_ldsx(void) { RUN(verifier_ldsx); }
|
||||
|
|
|
|||
113
tools/testing/selftests/bpf/progs/verifier_kfunc_uninit_multi.c
Normal file
113
tools/testing/selftests/bpf/progs/verifier_kfunc_uninit_multi.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
|
||||
|
||||
#include <vmlinux.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include "bpf_misc.h"
|
||||
#include "../test_kmods/bpf_testmod_kfunc.h"
|
||||
|
||||
/* Keep the kfunc BTF records used by the inline assembly. */
|
||||
void __kfunc_btf_root(void)
|
||||
{
|
||||
asm volatile ("" :
|
||||
: "r"(&bpf_kfunc_test_uninit_multi),
|
||||
"r"(&bpf_kfunc_test_uninit_pair),
|
||||
"r"(&bpf_kfunc_test_uninit_stack));
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
__success __retval(42)
|
||||
__flag(BPF_F_TEST_STATE_FREQ)
|
||||
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
|
||||
__prepare_priv
|
||||
__success_unpriv
|
||||
__naked void multiple_outputs(void)
|
||||
{
|
||||
asm volatile (
|
||||
"*(u64 *)(r10 - 16) = 0;"
|
||||
"*(u64 *)(r10 - 8) = 0;"
|
||||
"goto +0;"
|
||||
"r1 = r10;"
|
||||
"r1 += -16;"
|
||||
"r2 = r10;"
|
||||
"r2 += -8;"
|
||||
"r3 = 8;"
|
||||
"call %[bpf_kfunc_test_uninit_multi];"
|
||||
"r0 = *(u32 *)(r10 - 16);"
|
||||
"r1 = *(u32 *)(r10 - 8);"
|
||||
"if r1 != 0x2a2a2a2a goto 1f;"
|
||||
"r1 = *(u32 *)(r10 - 4);"
|
||||
"if r1 == 0x2a2a2a2a goto 2f;"
|
||||
"1:;"
|
||||
"r0 = 0;"
|
||||
"2:;"
|
||||
"exit;"
|
||||
: : __imm(bpf_kfunc_test_uninit_multi) : __clobber_all);
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
__success __retval(42)
|
||||
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
|
||||
__prepare_priv
|
||||
__success_unpriv
|
||||
__naked void variable_size_preserves_other_output(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r3 = *(u32 *)(r1 + 0);"
|
||||
"r3 &= 7;"
|
||||
"*(u64 *)(r10 - 8) = 0;"
|
||||
"r1 = r10;"
|
||||
"r1 += -16;"
|
||||
"r2 = r10;"
|
||||
"r2 += -8;"
|
||||
"call %[bpf_kfunc_test_uninit_multi];"
|
||||
"r0 = *(u32 *)(r10 - 16);"
|
||||
"exit;"
|
||||
: : __imm(bpf_kfunc_test_uninit_multi) : __clobber_all);
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
__arch_x86_64 __arch_arm64
|
||||
__success __retval(42)
|
||||
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
|
||||
__prepare_priv
|
||||
__success_unpriv
|
||||
__naked void output_after_by_value_argument(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r1 = 20;"
|
||||
"r2 = 22;"
|
||||
"r3 = r10;"
|
||||
"r3 += -8;"
|
||||
"call %[bpf_kfunc_test_uninit_pair];"
|
||||
"r0 = *(u32 *)(r10 - 8);"
|
||||
"exit;"
|
||||
: : __imm(bpf_kfunc_test_uninit_pair) : __clobber_all);
|
||||
}
|
||||
|
||||
#if defined(__BPF_FEATURE_STACK_ARGUMENT)
|
||||
SEC("tc")
|
||||
__arch_x86_64 __arch_arm64 __arch_riscv64
|
||||
__success __retval(15)
|
||||
__caps_unpriv(CAP_BPF | CAP_NET_ADMIN)
|
||||
__prepare_priv
|
||||
__success_unpriv
|
||||
__naked void output_passed_on_stack(void)
|
||||
{
|
||||
asm volatile (
|
||||
"r1 = 1;"
|
||||
"r2 = 2;"
|
||||
"r3 = 3;"
|
||||
"r4 = 4;"
|
||||
"r5 = 5;"
|
||||
"r6 = r10;"
|
||||
"r6 += -8;"
|
||||
"*(u64 *)(r11 - 8) = r6;"
|
||||
"call %[bpf_kfunc_test_uninit_stack];"
|
||||
"r0 = *(u32 *)(r10 - 8);"
|
||||
"exit;"
|
||||
: : __imm(bpf_kfunc_test_uninit_stack) : __clobber_all);
|
||||
}
|
||||
#endif
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
|
|
@ -1338,6 +1338,23 @@ __bpf_kfunc int bpf_kfunc_test_uninit_alias(int *out__uninit, const int *in)
|
|||
return value;
|
||||
}
|
||||
|
||||
__bpf_kfunc void bpf_kfunc_test_uninit_multi(int *a__uninit, void *b__uninit, u32 b__sz)
|
||||
{
|
||||
put_unaligned(42, a__uninit);
|
||||
memset(b__uninit, 0x2a, b__sz);
|
||||
}
|
||||
|
||||
__bpf_kfunc void bpf_kfunc_test_uninit_pair(struct prog_test_pair_arg p, int *out__uninit)
|
||||
{
|
||||
put_unaligned((int)(p.lo + p.hi), out__uninit);
|
||||
}
|
||||
|
||||
__bpf_kfunc void bpf_kfunc_test_uninit_stack(u64 a, u64 b, u64 c, u64 d, u64 e,
|
||||
int *out__uninit)
|
||||
{
|
||||
put_unaligned((int)(a + b + c + d + e), out__uninit);
|
||||
}
|
||||
|
||||
__bpf_kfunc void bpf_kfunc_call_test_fail1(struct prog_test_fail1 *p)
|
||||
{
|
||||
}
|
||||
|
|
@ -1772,6 +1789,9 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test_pass2)
|
|||
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_struct)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_mem)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_alias)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_multi)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_pair)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_test_uninit_stack)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail1)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail2)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_call_test_fail3)
|
||||
|
|
|
|||
|
|
@ -292,6 +292,10 @@ void bpf_kfunc_call_test_pass2(struct prog_test_pass2 *p) __ksym;
|
|||
void bpf_kfunc_test_uninit_struct(struct prog_test_pass1 *out__uninit) __ksym;
|
||||
void bpf_kfunc_test_uninit_mem(void *out__uninit, __u32 out__sz) __ksym;
|
||||
int bpf_kfunc_test_uninit_alias(int *out__uninit, const int *in) __ksym;
|
||||
void bpf_kfunc_test_uninit_multi(int *a__uninit, void *b__uninit, __u32 b__sz) __ksym;
|
||||
void bpf_kfunc_test_uninit_pair(struct prog_test_pair_arg p, int *out__uninit) __ksym;
|
||||
void bpf_kfunc_test_uninit_stack(__u64 a, __u64 b, __u64 c, __u64 d, __u64 e,
|
||||
int *out__uninit) __ksym;
|
||||
void bpf_kfunc_call_test_mem_len_fail2(__u64 *mem, int len) __ksym;
|
||||
|
||||
void bpf_kfunc_call_test_destructive(void) __ksym;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user