Similar to the previous patch, barrier_var() is used to prevent the LLVM23 compiler from optimizing away the return value of subprogs that issue a bpf_tail_call. Where the caller does not already consume the return value, store it into a global variable as well, so the compiler cannot change the subprog return type from 'int' to 'void'. Signed-off-by: Yonghong Song --- .../selftests/bpf/progs/tailcall_bpf2bpf2.c | 5 ++++- .../bpf/progs/tailcall_bpf2bpf_hierarchy2.c | 18 +++++++++++++----- .../bpf/progs/tailcall_bpf2bpf_hierarchy3.c | 11 ++++++++--- .../selftests/bpf/progs/verifier_sock.c | 9 +++++++-- 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf2.c b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf2.c index ce97d141daee..c4fadee5aadc 100644 --- a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf2.c +++ b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf2.c @@ -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; diff --git a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy2.c b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy2.c index ae94c9c70ab7..8f217bef3d62 100644 --- a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy2.c +++ b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy2.c @@ -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,21 @@ 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; } +int ret1, ret2; + __auxiliary SEC("tc") int classifier_1(struct __sk_buff *skb) { count1++; - subprog_tail1(skb); + ret1 = subprog_tail1(skb); return 0; } @@ -63,8 +71,8 @@ int tailcall_bpf2bpf_hierarchy_2(struct __sk_buff *skb) clobber_regs_stack(); - subprog_tail0(skb); - subprog_tail1(skb); + ret1 = subprog_tail0(skb); + ret2 = subprog_tail1(skb); __sink(ret); return (count1 << 16) | count0; diff --git a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy3.c b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy3.c index 56b6b0099840..4d89eabe1f70 100644 --- a/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy3.c +++ b/tools/testing/selftests/bpf/progs/tailcall_bpf2bpf_hierarchy3.c @@ -33,17 +33,22 @@ 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; } +int ret1, ret2; + __auxiliary SEC("tc") int classifier_0(struct __sk_buff *skb) { count++; - subprog_tail(skb, &jmp_table0); - subprog_tail(skb, &jmp_table1); + ret1 = subprog_tail(skb, &jmp_table0); + ret2 = subprog_tail(skb, &jmp_table1); return count; } diff --git a/tools/testing/selftests/bpf/progs/verifier_sock.c b/tools/testing/selftests/bpf/progs/verifier_sock.c index 9f680cf44512..bd9fa6b2a2f9 100644 --- a/tools/testing/selftests/bpf/progs/verifier_sock.c +++ b/tools/testing/selftests/bpf/progs/verifier_sock.c @@ -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. */ @@ -1138,6 +1141,8 @@ int invalidate_pkt_pointers_by_global_tail_call(struct __sk_buff *sk) return TCX_PASS; } +int ret1; + /* Tail calls in static sub-programs invalidate packet pointers. */ SEC("tc") __failure __msg("invalid mem access") @@ -1147,7 +1152,7 @@ int invalidate_pkt_pointers_by_static_tail_call(struct __sk_buff *sk) if ((void *)(p + 1) > (void *)(long)sk->data_end) return TCX_DROP; - static_tail_call(sk); + ret1 = static_tail_call(sk); *p = 42; /* this is unsafe */ return TCX_PASS; } -- 2.53.0-Meta