mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
Merge branch 'bpf-bound-rdonly-rdwr_buf_size-kfunc-return-size'
Nicholas Dudar says: ==================== bpf: bound rdonly/rdwr_buf_size kfunc return size check_kfunc_args() stores a kfunc's rdonly_buf_size/rdwr_buf_size argument into a u64 that check_kfunc_call() later narrows into the returned register's u32 mem_size, so a value above U32_MAX truncates instead of being rejected. Fix it and add a selftest for coverage. Changelog: ---------- v1 -> v2 (v1 was a private report to security@kernel.org) * Split the fix and selftest into separate patches. * Target bpf-next instead of bpf. ==================== Link: https://patch.msgid.link/20260709155837.1879230-1-main.kalliope@gmail.com Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
commit
a4553044d1
|
|
@ -12109,6 +12109,11 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
|
|||
}
|
||||
|
||||
meta->r0_size = reg->var_off.value;
|
||||
if (meta->r0_size > U32_MAX) {
|
||||
verbose(env, "%s rdonly/rdwr_buf_size exceeds u32 max\n",
|
||||
reg_arg_name(env, argno));
|
||||
return -EINVAL;
|
||||
}
|
||||
if (regno >= 0)
|
||||
ret = mark_chain_precision(env, regno);
|
||||
else
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user