• Ilya Leoshkevich's avatar
    bpf: fix narrower loads on s390 · d9b8aada
    Ilya Leoshkevich authored
    The very first check in test_pkt_md_access is failing on s390, which
    happens because loading a part of a struct __sk_buff field produces
    an incorrect result.
    
    The preprocessed code of the check is:
    
    {
    	__u8 tmp = *((volatile __u8 *)&skb->len +
    		((sizeof(skb->len) - sizeof(__u8)) / sizeof(__u8)));
    	if (tmp != ((*(volatile __u32 *)&skb->len) & 0xFF)) return 2;
    };
    
    clang generates the following code for it:
    
          0:	71 21 00 03 00 00 00 00	r2 = *(u8 *)(r1 + 3)
          1:	61 31 00 00 00 00 00 00	r3 = *(u32 *)(r1 + 0)
          2:	57 30 00 00 00 00 00 ff	r3 &= 255
          3:	5d 23 00 1d 00 00 00 00	if r2 != r3 goto +29 <LBB0_10>
    
    Finally, verifier transforms it to:
    
      0: (61) r2 = *(u32 *)(r1 +104)
      1: (bc) w2 = w2
      2: (74) w2 >>= 24
      3: (bc) w2 = w2
      4: (54) w2 &= 255
      5: (bc) w2 = w2
    
    The problem is that when verifier emits the code to replace a partial
    load of a struct __sk_buff field (*(u8 *)(r1 + 3)) with a full load of
    struct sk_buff field (*(u32 *)(r1 + 104)), an optional shift and a
    bitwise AND, it assumes that the machine is little endian and
    incorrectly decides to use a shift.
    
    Adjust shift count calculation to account for endianness.
    
    Fixes: 31fd8581 ("bpf: permits narrower load from bpf program context fields")
    Signed-off-by: default avatarIlya Leoshkevich <iii@linux.ibm.com>
    Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    d9b8aada
verifier.c 268 KB