1 From pulehui@huaweicloud.com Fri Aug 4 17:25:37 2023
2 From: Pu Lehui <pulehui@huaweicloud.com>
3 Date: Fri, 4 Aug 2023 23:24:58 +0800
4 Subject: selftests/bpf: Workaround verification failure for fexit_bpf2bpf/func_replace_return_code
5 To: stable@vger.kernel.org, Greg KH <greg@kroah.com>, Eduard Zingerman <eddyz87@gmail.com>, Luiz Capitulino <luizcap@amazon.com>
6 Cc: Alexei Starovoitov <ast@kernel.org>, Daniel Borkmann <daniel@iogearbox.net>, Andrii Nakryiko <andrii@kernel.org>, Pu Lehui <pulehui@huawei.com>, Pu Lehui <pulehui@huaweicloud.com>
7 Message-ID: <20230804152459.2565673-6-pulehui@huaweicloud.com>
9 From: Yonghong Song <yhs@fb.com>
11 [ Upstream commit 63d78b7e8ca2d0eb8c687a355fa19d01b6fcc723 ]
13 With latest llvm17, selftest fexit_bpf2bpf/func_replace_return_code
14 has the following verification failure:
16 0: R1=ctx(off=0,imm=0) R10=fp0
17 ; int connect_v4_prog(struct bpf_sock_addr *ctx)
18 0: (bf) r7 = r1 ; R1=ctx(off=0,imm=0) R7_w=ctx(off=0,imm=0)
19 1: (b4) w6 = 0 ; R6_w=0
20 ; memset(&tuple.ipv4.saddr, 0, sizeof(tuple.ipv4.saddr));
22 ; return do_bind(ctx) ? 1 : 0;
23 179: (bf) r1 = r7 ; R1=ctx(off=0,imm=0) R7=ctx(off=0,imm=0)
25 Func#3 is global and valid. Skipping.
27 181: (bc) w6 = w0 ; R0_w=scalar() R6_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff))
30 54: (bc) w0 = w6 ; R0_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff)) R6_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff))
32 At program exit the register R0 has value (0x0; 0xffffffff) should have been in (0x0; 0x1)
33 processed 281 insns (limit 1000000) max_states_per_insn 1 total_states 26 peak_states 26 mark_read 13
34 -- END PROG LOAD LOG --
35 libbpf: prog 'connect_v4_prog': failed to load: -22
37 The corresponding source code:
39 __attribute__ ((noinline))
40 int do_bind(struct bpf_sock_addr *ctx)
42 struct sockaddr_in sa = {};
44 sa.sin_family = AF_INET;
45 sa.sin_port = bpf_htons(0);
46 sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4);
48 if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0)
54 SEC("cgroup/connect4")
55 int connect_v4_prog(struct bpf_sock_addr *ctx)
58 return do_bind(ctx) ? 1 : 0;
61 Insn 180 is a call to 'do_bind'. The call's return value is also the return value
62 for the program. Since do_bind() returns 0/1, so it is legitimate for compiler to
63 optimize 'return do_bind(ctx) ? 1 : 0' to 'return do_bind(ctx)'. However, such
64 optimization breaks verifier as the return value of 'do_bind()' is marked as any
65 scalar which violates the requirement of prog return value 0/1.
67 There are two ways to fix this problem, (1) changing 'return 1' in do_bind() to
68 e.g. 'return 10' so the compiler has to do 'do_bind(ctx) ? 1 :0', or (2)
69 suggested by Andrii, marking do_bind() with __weak attribute so the compiler
70 cannot make any assumption on do_bind() return value.
72 This patch adopted adding __weak approach which is simpler and more resistant
73 to potential compiler optimizations.
75 Suggested-by: Andrii Nakryiko <andrii@kernel.org>
76 Signed-off-by: Yonghong Song <yhs@fb.com>
77 Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
78 Link: https://lore.kernel.org/bpf/20230310012410.2920570-1-yhs@fb.com
79 Signed-off-by: Pu Lehui <pulehui@huawei.com>
80 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
82 tools/testing/selftests/bpf/progs/connect4_prog.c | 2 +-
83 1 file changed, 1 insertion(+), 1 deletion(-)
85 --- a/tools/testing/selftests/bpf/progs/connect4_prog.c
86 +++ b/tools/testing/selftests/bpf/progs/connect4_prog.c
89 int _version SEC("version") = 1;
91 -__attribute__ ((noinline))
92 +__attribute__ ((noinline)) __weak
93 int do_bind(struct bpf_sock_addr *ctx)
95 struct sockaddr_in sa = {};