mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
selftests/bpf: Keep int return type for tailcall subprogs
LLVM23 ([1]) supports 'true' function signature in BTF. The return type of the caller of a tailcall must be an 'int'. Otherwise, verification will fail (see check_btf_func() in check_btf.c). So with llvm23, it is possible that the compiler may change the caller's return type from 'int' to 'void'. To prevent this, barrier_var() and __sink() are used to avoid returning a constant prone to be optimized. [1] https://github.com/llvm/llvm-project/pull/198426 Signed-off-by: Yonghong Song <yonghong.song@linux.dev> Link: https://lore.kernel.org/r/20260609233407.2711577-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
c15261b1bb
commit
be1d838b88
|
|
@ -13,11 +13,14 @@ struct {
|
|||
static __noinline
|
||||
int subprog_tail(struct __sk_buff *skb)
|
||||
{
|
||||
int ret = 1;
|
||||
|
||||
if (load_byte(skb, 0))
|
||||
bpf_tail_call_static(skb, &jmp_table, 1);
|
||||
else
|
||||
bpf_tail_call_static(skb, &jmp_table, 0);
|
||||
return 1;
|
||||
barrier_var(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int count = 0;
|
||||
|
|
|
|||
|
|
@ -16,20 +16,25 @@ int count = 0;
|
|||
static __noinline
|
||||
int subprog_tail(struct __sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_tail_call_static(skb, &jmp_table, 0);
|
||||
return 0;
|
||||
barrier_var(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEC("tc")
|
||||
int entry(struct __sk_buff *skb)
|
||||
{
|
||||
int ret = 1;
|
||||
int ret = 1, ret1, ret2;
|
||||
|
||||
clobber_regs_stack();
|
||||
|
||||
count++;
|
||||
subprog_tail(skb);
|
||||
subprog_tail(skb);
|
||||
ret1 = subprog_tail(skb);
|
||||
ret2 = subprog_tail(skb);
|
||||
__sink(ret1);
|
||||
__sink(ret2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,11 @@ int count1 = 0;
|
|||
static __noinline
|
||||
int subprog_tail0(struct __sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_tail_call_static(skb, &jmp_table, 0);
|
||||
return 0;
|
||||
barrier_var(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__auxiliary
|
||||
|
|
@ -41,16 +44,22 @@ int classifier_0(struct __sk_buff *skb)
|
|||
static __noinline
|
||||
int subprog_tail1(struct __sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_tail_call_static(skb, &jmp_table, 1);
|
||||
return 0;
|
||||
barrier_var(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__auxiliary
|
||||
SEC("tc")
|
||||
int classifier_1(struct __sk_buff *skb)
|
||||
{
|
||||
int ret;
|
||||
|
||||
count1++;
|
||||
subprog_tail1(skb);
|
||||
ret = subprog_tail1(skb);
|
||||
__sink(ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -59,13 +68,14 @@ __retval(33)
|
|||
SEC("tc")
|
||||
int tailcall_bpf2bpf_hierarchy_2(struct __sk_buff *skb)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret = 0, ret1, ret2;
|
||||
|
||||
clobber_regs_stack();
|
||||
|
||||
subprog_tail0(skb);
|
||||
subprog_tail1(skb);
|
||||
|
||||
ret1 = subprog_tail0(skb);
|
||||
ret2 = subprog_tail1(skb);
|
||||
__sink(ret1);
|
||||
__sink(ret2);
|
||||
__sink(ret);
|
||||
return (count1 << 16) | count0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,17 +33,24 @@ int count = 0;
|
|||
static __noinline
|
||||
int subprog_tail(struct __sk_buff *skb, void *jmp_table)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_tail_call_static(skb, jmp_table, 0);
|
||||
return 0;
|
||||
barrier_var(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
__auxiliary
|
||||
SEC("tc")
|
||||
int classifier_0(struct __sk_buff *skb)
|
||||
{
|
||||
int ret1, ret2;
|
||||
|
||||
count++;
|
||||
subprog_tail(skb, &jmp_table0);
|
||||
subprog_tail(skb, &jmp_table1);
|
||||
ret1 = subprog_tail(skb, &jmp_table0);
|
||||
ret2 = subprog_tail(skb, &jmp_table1);
|
||||
__sink(ret1);
|
||||
__sink(ret2);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -18,18 +18,25 @@ int count = 0;
|
|||
static __noinline
|
||||
int subprog_tail(void *ctx)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_tail_call_static(ctx, &jmp_table, 0);
|
||||
return 0;
|
||||
barrier_var(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
SEC("fentry/dummy")
|
||||
int BPF_PROG(fentry, struct sk_buff *skb)
|
||||
{
|
||||
int ret1, ret2;
|
||||
|
||||
clobber_regs_stack();
|
||||
|
||||
count++;
|
||||
subprog_tail(ctx);
|
||||
subprog_tail(ctx);
|
||||
ret1 = subprog_tail(ctx);
|
||||
ret2 = subprog_tail(ctx);
|
||||
__sink(ret1);
|
||||
__sink(ret2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1120,8 +1120,11 @@ int tail_call(struct __sk_buff *sk)
|
|||
static __noinline
|
||||
int static_tail_call(struct __sk_buff *sk)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
bpf_tail_call_static(sk, &jmp_table, 0);
|
||||
return 0;
|
||||
barrier_var(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Tail calls in sub-programs invalidate packet pointers. */
|
||||
|
|
@ -1144,10 +1147,12 @@ __failure __msg("invalid mem access")
|
|||
int invalidate_pkt_pointers_by_static_tail_call(struct __sk_buff *sk)
|
||||
{
|
||||
int *p = (void *)(long)sk->data;
|
||||
int ret;
|
||||
|
||||
if ((void *)(p + 1) > (void *)(long)sk->data_end)
|
||||
return TCX_DROP;
|
||||
static_tail_call(sk);
|
||||
ret = static_tail_call(sk);
|
||||
__sink(ret);
|
||||
*p = 42; /* this is unsafe */
|
||||
return TCX_PASS;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user