selftests/bpf: Add test for oversized rdonly/rdwr_buf_size kfunc argument

Add a load-failure test to the kfunc_call suite using the existing
bpf_kfunc_call_test_get_rdwr_mem() test kfunc. Its rdwr_buf_size
argument is a const int, so the test uses a 64-bit immediate load in
inline asm to place 2^64 - 192 (0xffffffffffffff40) in the argument
register. The verifier records r0_size from the full 64-bit register
value, and the test asserts that BPF_PROG_LOAD rejects it with
"rdonly/rdwr_buf_size exceeds u32 max".

Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/bpf/20260709155837.1879230-3-main.kalliope@gmail.com
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
Nicholas Dudar 2026-07-09 11:58:37 -04:00 committed by Kumar Kartikeya Dwivedi
parent 2aaf67f051
commit 12556c3198
No known key found for this signature in database
GPG Key ID: 472D377B63542F83
2 changed files with 34 additions and 0 deletions

View File

@ -66,6 +66,7 @@ static struct kfunc_test_params kfunc_tests[] = {
TC_FAIL(kfunc_call_test_get_mem_fail_rdonly, 0, "R0 cannot write into rdonly_mem"),
TC_FAIL(kfunc_call_test_get_mem_fail_use_after_free, 0, "invalid mem access 'scalar'"),
TC_FAIL(kfunc_call_test_get_mem_fail_oob, 0, "min value is outside of the allowed memory range"),
TC_FAIL(kfunc_call_test_get_mem_fail_oversized, 0, "rdonly/rdwr_buf_size exceeds u32 max"),
TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"),
TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function does not return PTR_TO_BTF_ID"),
TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "R1 expected pointer to ctx, but got scalar"),

View File

@ -103,6 +103,39 @@ int kfunc_call_test_get_mem_fail_oob(struct __sk_buff *skb)
return ret;
}
SEC("?tc")
int kfunc_call_test_get_mem_fail_oversized(struct __sk_buff *skb)
{
struct prog_test_ref_kfunc *pt;
unsigned long s = 0;
int *p = NULL;
int ret = 0;
pt = bpf_kfunc_call_test_acquire(&s);
if (pt) {
/*
* rdwr_buf_size is a const int, so a C literal is narrowed to
* 32 bits before the call. Force the full 64-bit value 2^64 - 192
* (0xffffffffffffff40, > U32_MAX) into the argument register with
* a 64-bit immediate load. The verifier records r0_size from the
* full register value and must reject it before that value is
* truncated into R0's u32 mem_size.
*/
asm volatile (
"r1 = %[pt];"
"r2 = %[oversized] ll;"
"call %[get_rdwr_mem];"
"%[p] = r0;"
: [p] "=r"(p)
: [pt] "r"(pt),
[oversized] "i"(0xffffffffffffff40LL),
[get_rdwr_mem] "i"(bpf_kfunc_call_test_get_rdwr_mem)
: "r0", "r1", "r2", "r3", "r4", "r5");
bpf_kfunc_call_test_release(pt);
}
return ret;
}
int not_const_size = 2 * sizeof(int);
SEC("?tc")