• Daniel Borkmann's avatar
    bpf: fix inner map masking to prevent oob under speculation · 9d5564dd
    Daniel Borkmann authored
    During review I noticed that inner meta map setup for map in
    map is buggy in that it does not propagate all needed data
    from the reference map which the verifier is later accessing.
    
    In particular one such case is index masking to prevent out of
    bounds access under speculative execution due to missing the
    map's unpriv_array/index_mask field propagation. Fix this such
    that the verifier is generating the correct code for inlined
    lookups in case of unpriviledged use.
    
    Before patch (test_verifier's 'map in map access' dump):
    
      # bpftool prog dump xla id 3
         0: (62) *(u32 *)(r10 -4) = 0
         1: (bf) r2 = r10
         2: (07) r2 += -4
         3: (18) r1 = map[id:4]
         5: (07) r1 += 272                |
         6: (61) r0 = *(u32 *)(r2 +0)     |
         7: (35) if r0 >= 0x1 goto pc+6   | Inlined map in map lookup
         8: (54) (u32) r0 &= (u32) 0      | with index masking for
         9: (67) r0 <<= 3                 | map->unpriv_array.
        10: (0f) r0 += r1                 |
        11: (79) r0 = *(u64 *)(r0 +0)     |
        12: (15) if r0 == 0x0 goto pc+1   |
        13: (05) goto pc+1                |
        14: (b7) r0 = 0                   |
        15: (15) if r0 == 0x0 goto pc+11
        16: (62) *(u32 *)(r10 -4) = 0
        17: (bf) r2 = r10
        18: (07) r2 += -4
        19: (bf) r1 = r0
        20: (07) r1 += 272                |
        21: (61) r0 = *(u32 *)(r2 +0)     | Index masking missing (!)
        22: (35) if r0 >= 0x1 goto pc+3   | for inner map despite
        23: (67) r0 <<= 3                 | map->unpriv_array set.
        24: (0f) r0 += r1                 |
        25: (05) goto pc+1                |
        26: (b7) r0 = 0                   |
        27: (b7) r0 = 0
        28: (95) exit
    
    After patch:
    
      # bpftool prog dump xla id 1
         0: (62) *(u32 *)(r10 -4) = 0
         1: (bf) r2 = r10
         2: (07) r2 += -4
         3: (18) r1 = map[id:2]
         5: (07) r1 += 272                |
         6: (61) r0 = *(u32 *)(r2 +0)     |
         7: (35) if r0 >= 0x1 goto pc+6   | Same inlined map in map lookup
         8: (54) (u32) r0 &= (u32) 0      | with index masking due to
         9: (67) r0 <<= 3                 | map->unpriv_array.
        10: (0f) r0 += r1                 |
        11: (79) r0 = *(u64 *)(r0 +0)     |
        12: (15) if r0 == 0x0 goto pc+1   |
        13: (05) goto pc+1                |
        14: (b7) r0 = 0                   |
        15: (15) if r0 == 0x0 goto pc+12
        16: (62) *(u32 *)(r10 -4) = 0
        17: (bf) r2 = r10
        18: (07) r2 += -4
        19: (bf) r1 = r0
        20: (07) r1 += 272                |
        21: (61) r0 = *(u32 *)(r2 +0)     |
        22: (35) if r0 >= 0x1 goto pc+4   | Now fixed inlined inner map
        23: (54) (u32) r0 &= (u32) 0      | lookup with proper index masking
        24: (67) r0 <<= 3                 | for map->unpriv_array.
        25: (0f) r0 += r1                 |
        26: (05) goto pc+1                |
        27: (b7) r0 = 0                   |
        28: (b7) r0 = 0
        29: (95) exit
    
    Fixes: b2157399 ("bpf: prevent out-of-bounds speculation")
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Acked-by: default avatarMartin KaFai Lau <kafai@fb.com>
    Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
    9d5564dd
map_in_map.c 3.01 KB