mirror of
https://github.com/torvalds/linux.git
synced 2026-09-26 01:52:03 +02:00
selftests/bpf: Test a multi-slot argument before a struct_ops arena argument
The trampoline reads the __arena flag from the btf_func_model per argument but stores the ctx one register slot at a time, so the two only line up if every preceding argument occupies exactly one slot. Every arena-bearing member of bpf_testmod_ops3 takes single-slot arguments, so nothing exercises the mapping and a mis-indexed arg_flags lookup would go unnoticed on any architecture. Add test_arena_multislot(), whose first argument is a 16-byte struct passed by value. It fills ctx[0] and ctx[1], putting the arena pointer at argument index one but slot two. The callback checks both halves of the struct before dereferencing ctx[2], so a JIT that walks registers instead of arguments converts the wrong slot and fails the test. Signed-off-by: Puranjay Mohan <puranjay@kernel.org> Acked-by: Xu Kuohai <xukuohai@huawei.com> Link: https://lore.kernel.org/bpf/20260813190356.335181-8-puranjay@kernel.org Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
parent
05a3575f22
commit
197d34b169
|
|
@ -59,11 +59,28 @@ int test_arena_stack_cb(unsigned long long *ctx)
|
|||
return 0;
|
||||
}
|
||||
|
||||
SEC("struct_ops/test_arena_multislot")
|
||||
int test_arena_multislot_cb(unsigned long long *ctx)
|
||||
{
|
||||
u64 __arena *ptr = (u64 __arena *)ctx[2];
|
||||
|
||||
arena_touch++;
|
||||
/*
|
||||
* The 16-byte struct occupies ctx[0] and ctx[1], so @ptr is argument
|
||||
* one but slot two. Getting that wrong hands the callback a scalar.
|
||||
*/
|
||||
if (ctx[0] != 11 || ctx[1] != 22)
|
||||
return 0xbad;
|
||||
*ptr += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC(".struct_ops.link")
|
||||
struct bpf_testmod_ops3 testmod_arena = {
|
||||
.test_arena = (void *)test_arena_cb,
|
||||
.test_arena_nullable = (void *)test_arena_nullable_cb,
|
||||
.test_arena_stack = (void *)test_arena_stack_cb,
|
||||
.test_arena_multislot = (void *)test_arena_multislot_cb,
|
||||
};
|
||||
|
||||
SEC("syscall")
|
||||
|
|
@ -109,6 +126,13 @@ int trigger(void *ctx)
|
|||
if (*val != 44)
|
||||
return 9;
|
||||
|
||||
/* a multi-slot arg precedes the arena pointer here */
|
||||
ret = bpf_testmod_ops3_call_test_arena_multislot((u64 *)val);
|
||||
if (ret)
|
||||
return 10;
|
||||
if (*val != 45)
|
||||
return 11;
|
||||
|
||||
bpf_arena_free_pages(&arena, (void __arena *)val, 1);
|
||||
#endif
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -402,12 +402,19 @@ static int bpf_testmod_ops3__test_arena_stack(u64 a, u64 b, u64 c, u64 d,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bpf_testmod_ops3__test_arena_multislot(struct bpf_testmod_arena_pair p,
|
||||
u64 *ptr__arena)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct bpf_testmod_ops3 __bpf_testmod_ops3 = {
|
||||
.test_1 = bpf_testmod_test_3,
|
||||
.test_2 = bpf_testmod_test_4,
|
||||
.test_arena = bpf_testmod_ops3__test_arena,
|
||||
.test_arena_nullable = bpf_testmod_ops3__test_arena_nullable,
|
||||
.test_arena_stack = bpf_testmod_ops3__test_arena_stack,
|
||||
.test_arena_multislot = bpf_testmod_ops3__test_arena_multislot,
|
||||
};
|
||||
|
||||
static void bpf_testmod_test_struct_ops3(void)
|
||||
|
|
@ -441,6 +448,13 @@ __bpf_kfunc int bpf_testmod_ops3_call_test_arena_stack(u64 *ptr__arena)
|
|||
return st_ops3->test_arena_stack(1, 2, 3, 4, 5, 6, 7, 8, ptr__arena);
|
||||
}
|
||||
|
||||
__bpf_kfunc int bpf_testmod_ops3_call_test_arena_multislot(u64 *ptr__arena)
|
||||
{
|
||||
struct bpf_testmod_arena_pair p = { .a = 11, .b = 22 };
|
||||
|
||||
return st_ops3->test_arena_multislot(p, ptr__arena);
|
||||
}
|
||||
|
||||
struct bpf_testmod_btf_type_tag_1 {
|
||||
int a;
|
||||
};
|
||||
|
|
@ -852,6 +866,7 @@ BTF_ID_FLAGS(func, bpf_testmod_ops3_call_test_2)
|
|||
BTF_ID_FLAGS(func, bpf_testmod_ops3_call_test_arena)
|
||||
BTF_ID_FLAGS(func, bpf_testmod_ops3_call_test_arena_nullable)
|
||||
BTF_ID_FLAGS(func, bpf_testmod_ops3_call_test_arena_stack)
|
||||
BTF_ID_FLAGS(func, bpf_testmod_ops3_call_test_arena_multislot)
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_get_default_trusted_ptr_test);
|
||||
BTF_ID_FLAGS(func, bpf_kfunc_put_default_trusted_ptr_test);
|
||||
BTF_KFUNCS_END(bpf_testmod_common_kfunc_ids)
|
||||
|
|
|
|||
|
|
@ -103,6 +103,12 @@ struct bpf_testmod_ops2 {
|
|||
int (*test_1)(void);
|
||||
};
|
||||
|
||||
/* 16 bytes, so it takes two argument slots when passed by value */
|
||||
struct bpf_testmod_arena_pair {
|
||||
u64 a;
|
||||
u64 b;
|
||||
};
|
||||
|
||||
struct bpf_testmod_ops3 {
|
||||
int (*test_1)(void);
|
||||
int (*test_2)(void);
|
||||
|
|
@ -112,6 +118,8 @@ struct bpf_testmod_ops3 {
|
|||
/* enough leading args to force @ptr onto the stack on x86 and arm64 */
|
||||
int (*test_arena_stack)(u64 a, u64 b, u64 c, u64 d, u64 e, u64 f,
|
||||
u64 g, u64 h, u64 *ptr);
|
||||
/* a multi-slot leading arg, so @ptr is not at the slot its arg index suggests */
|
||||
int (*test_arena_multislot)(struct bpf_testmod_arena_pair p, u64 *ptr);
|
||||
};
|
||||
|
||||
struct st_ops_args {
|
||||
|
|
|
|||
|
|
@ -123,6 +123,7 @@ void bpf_testmod_test_mod_kfunc(int i) __ksym;
|
|||
int bpf_testmod_ops3_call_test_arena(__u64 *ptr__arena) __ksym;
|
||||
int bpf_testmod_ops3_call_test_arena_nullable(__u64 *ptr__arena__nullable) __ksym;
|
||||
int bpf_testmod_ops3_call_test_arena_stack(__u64 *ptr__arena) __ksym;
|
||||
int bpf_testmod_ops3_call_test_arena_multislot(__u64 *ptr__arena) __ksym;
|
||||
|
||||
__u64 bpf_kfunc_call_test1(struct sock *sk, __u32 a, __u64 b,
|
||||
__u32 c, __u64 d) __ksym;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user