• Jakub Sitnicki's avatar
    selftests/bpf: Fix test for 4-byte load from dst_port on big-endian · deb59400
    Jakub Sitnicki authored
    The check for 4-byte load from dst_port offset into bpf_sock is failing on
    big-endian architecture - s390. The bpf access converter rewrites the
    4-byte load to a 2-byte load from sock_common at skc_dport offset, as shown
    below.
    
      * s390 / llvm-objdump -S --no-show-raw-insn
    
      00000000000002a0 <sk_dst_port__load_word>:
            84:       r1 = *(u32 *)(r1 + 48)
            85:       w0 = 1
            86:       if w1 == 51966 goto +1 <LBB5_2>
            87:       w0 = 0
      00000000000002c0 <LBB5_2>:
            88:       exit
    
      * s390 / bpftool prog dump xlated
    
      _Bool sk_dst_port__load_word(struct bpf_sock * sk):
        35: (69) r1 = *(u16 *)(r1 +12)
        36: (bc) w1 = w1
        37: (b4) w0 = 1
        38: (16) if w1 == 0xcafe goto pc+1
        39: (b4) w0 = 0
        40: (95) exit
    
      * x86_64 / llvm-objdump -S --no-show-raw-insn
    
      00000000000002a0 <sk_dst_port__load_word>:
            84:       r1 = *(u32 *)(r1 + 48)
            85:       w0 = 1
            86:       if w1 == 65226 goto +1 <LBB5_2>
            87:       w0 = 0
      00000000000002c0 <LBB5_2>:
            88:       exit
    
      * x86_64 / bpftool prog dump xlated
    
      _Bool sk_dst_port__load_word(struct bpf_sock * sk):
        33: (69) r1 = *(u16 *)(r1 +12)
        34: (b4) w0 = 1
        35: (16) if w1 == 0xfeca goto pc+1
        36: (b4) w0 = 0
        37: (95) exit
    
    This leads to surprises if we treat the destination register contents as a
    32-bit value, ignoring the fact that in reality it contains a 16-bit value.
    
    On little-endian the register contents reflect the bpf_sock struct
    definition, where the lower 16-bits contain the port number:
    
    	struct bpf_sock {
    		...
    		__be16 dst_port;	/* offset 48 */
    		__u16 :16;
    		...
    	};
    
    However, on big-endian the register contents suggest that field the layout
    of bpf_sock struct is as so:
    
    	struct bpf_sock {
    		...
    		__u16 :16;		/* offset 48 */
    		__be16 dst_port;
    		...
    	};
    
    Account for this quirky access conversion in the test case exercising the
    4-byte load by treating the result as 16-bit wide.
    Signed-off-by: default avatarJakub Sitnicki <jakub@cloudflare.com>
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
    Link: https://lore.kernel.org/bpf/20220317113920.1068535-5-jakub@cloudflare.com
    deb59400
test_sock_fields.c 7.25 KB