• Yonghong Song's avatar
    selftests/bpf: Fix dynptr/test_dynptr_is_null · 12852f8e
    Yonghong Song authored
    With latest llvm17, dynptr/test_dynptr_is_null subtest failed in my testing
    VM. The failure log looks like below:
    
      All error logs:
      tester_init:PASS:tester_log_buf 0 nsec
      process_subtest:PASS:obj_open_mem 0 nsec
      process_subtest:PASS:Can't alloc specs array 0 nsec
      verify_success:PASS:dynptr_success__open 0 nsec
      verify_success:PASS:bpf_object__find_program_by_name 0 nsec
      verify_success:PASS:dynptr_success__load 0 nsec
      verify_success:PASS:bpf_program__attach 0 nsec
      verify_success:FAIL:err unexpected err: actual 4 != expected 0
      #65/9    dynptr/test_dynptr_is_null:FAIL
    
    The error happens for bpf prog test_dynptr_is_null in dynptr_success.c:
    
            if (bpf_dynptr_is_null(&ptr2)) {
                    err = 4;
                    goto exit;
            }
    
    The bpf_dynptr_is_null(&ptr) unexpectedly returned a non-zero value and
    the control went to the error path. Digging further, I found the root cause
    is due to function signature difference between kernel and user space.
    
    In kernel, we have ...
    
      __bpf_kfunc bool bpf_dynptr_is_null(struct bpf_dynptr_kern *ptr)
    
    ... while in bpf_kfuncs.h we have:
    
      extern int bpf_dynptr_is_null(const struct bpf_dynptr *ptr) __ksym;
    
    The kernel bpf_dynptr_is_null disasm code:
    
      ffffffff812f1a90 <bpf_dynptr_is_null>:
      ffffffff812f1a90: f3 0f 1e fa           endbr64
      ffffffff812f1a94: 0f 1f 44 00 00        nopl    (%rax,%rax)
      ffffffff812f1a99: 53                    pushq   %rbx
      ffffffff812f1a9a: 48 89 fb              movq    %rdi, %rbx
      ffffffff812f1a9d: e8 ae 29 17 00        callq   0xffffffff81464450 <__asan_load8_noabort>
      ffffffff812f1aa2: 48 83 3b 00           cmpq    $0x0, (%rbx)
      ffffffff812f1aa6: 0f 94 c0              sete    %al
      ffffffff812f1aa9: 5b                    popq    %rbx
      ffffffff812f1aaa: c3                    retq
    
    Note that only 1-byte register %al is set and the other 7-bytes are not
    touched. In bpf program, the asm code for the above bpf_dynptr_is_null(&ptr2):
    
           266:       85 10 00 00 ff ff ff ff call -0x1
           267:       b4 01 00 00 04 00 00 00 w1 = 0x4
           268:       16 00 03 00 00 00 00 00 if w0 == 0x0 goto +0x3 <LBB9_8>
    
    Basically, 4-byte subregister is tested. This might cause error as the value
    other than the lowest byte might not be 0.
    
    This patch fixed the issue by using the identical func prototype across kernel
    and selftest user space. The fixed bpf asm code:
    
           267:       85 10 00 00 ff ff ff ff call -0x1
           268:       54 00 00 00 01 00 00 00 w0 &= 0x1
           269:       b4 01 00 00 04 00 00 00 w1 = 0x4
           270:       16 00 03 00 00 00 00 00 if w0 == 0x0 goto +0x3 <LBB9_8>
    Signed-off-by: default avatarYonghong Song <yhs@fb.com>
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Link: https://lore.kernel.org/bpf/20230517040404.4023912-1-yhs@fb.com
    12852f8e
dynptr_success.c 10.1 KB