• Yonghong Song's avatar
    selftests/bpf: Workaround verification failure for fexit_bpf2bpf/func_replace_return_code · 63d78b7e
    Yonghong Song authored
    With latest llvm17, selftest fexit_bpf2bpf/func_replace_return_code
    has the following verification failure:
    
      0: R1=ctx(off=0,imm=0) R10=fp0
      ; int connect_v4_prog(struct bpf_sock_addr *ctx)
      0: (bf) r7 = r1                       ; R1=ctx(off=0,imm=0) R7_w=ctx(off=0,imm=0)
      1: (b4) w6 = 0                        ; R6_w=0
      ; memset(&tuple.ipv4.saddr, 0, sizeof(tuple.ipv4.saddr));
      ...
      ; return do_bind(ctx) ? 1 : 0;
      179: (bf) r1 = r7                     ; R1=ctx(off=0,imm=0) R7=ctx(off=0,imm=0)
      180: (85) call pc+147
      Func#3 is global and valid. Skipping.
      181: R0_w=scalar()
      181: (bc) w6 = w0                     ; R0_w=scalar() R6_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff))
      182: (05) goto pc-129
      ; }
      54: (bc) w0 = w6                      ; R0_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff)) R6_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff))
      55: (95) exit
      At program exit the register R0 has value (0x0; 0xffffffff) should have been in (0x0; 0x1)
      processed 281 insns (limit 1000000) max_states_per_insn 1 total_states 26 peak_states 26 mark_read 13
      -- END PROG LOAD LOG --
      libbpf: prog 'connect_v4_prog': failed to load: -22
    
    The corresponding source code:
    
      __attribute__ ((noinline))
      int do_bind(struct bpf_sock_addr *ctx)
      {
            struct sockaddr_in sa = {};
    
            sa.sin_family = AF_INET;
            sa.sin_port = bpf_htons(0);
            sa.sin_addr.s_addr = bpf_htonl(SRC_REWRITE_IP4);
    
            if (bpf_bind(ctx, (struct sockaddr *)&sa, sizeof(sa)) != 0)
                    return 0;
    
            return 1;
      }
      ...
      SEC("cgroup/connect4")
      int connect_v4_prog(struct bpf_sock_addr *ctx)
      {
      ...
            return do_bind(ctx) ? 1 : 0;
      }
    
    Insn 180 is a call to 'do_bind'. The call's return value is also the return value
    for the program. Since do_bind() returns 0/1, so it is legitimate for compiler to
    optimize 'return do_bind(ctx) ? 1 : 0' to 'return do_bind(ctx)'. However, such
    optimization breaks verifier as the return value of 'do_bind()' is marked as any
    scalar which violates the requirement of prog return value 0/1.
    
    There are two ways to fix this problem, (1) changing 'return 1' in do_bind() to
    e.g. 'return 10' so the compiler has to do 'do_bind(ctx) ? 1 :0', or (2)
    suggested by Andrii, marking do_bind() with __weak attribute so the compiler
    cannot make any assumption on do_bind() return value.
    
    This patch adopted adding __weak approach which is simpler and more resistant
    to potential compiler optimizations.
    Suggested-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Signed-off-by: default avatarYonghong Song <yhs@fb.com>
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Link: https://lore.kernel.org/bpf/20230310012410.2920570-1-yhs@fb.com
    63d78b7e
connect4_prog.c 4.44 KB