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:
Kumar Kartikeya Dwivedi 2026-09-21 04:38:31 +02:00 committed by Alexei Starovoitov
parent bca730ba6d
commit 89835699ef
No known key found for this signature in database
4 changed files with 139 additions and 0 deletions

View File

@ -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); }

View 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";

View File

@ -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)

View File

@ -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;