Ebpf: Invalid access to map value, with weird compiled code

32 Views Asked by At

This is my ebpf source code. I have posted another question regarding a slightly different error but just adding it here for reference: Previous question. What happened here is that when I uncomment the commented out code and run the ebpf program, it gives this error:

permission denied: invalid access to map value, value_size=20 off=21 size=1: R2 max value is outside of the allowed memory range

This is weird because the program ran perfectly fine without the commented part and the logic is essentially the same for syn and fin flag.

struct value {
    int index;
    char flags[MAX_FLAGS_LEN];
};

static __always_inline void store_flags(struct value *value, struct tcphdr *tcp){
    __u8 index = value->index;

    if (index >= sizeof(value->flags)){
        return;
    }
    
    if (index < sizeof(value->flags)){
        if (tcp->syn){
            value->flags[index] = 'S';
            index++;
        }
    }

    if (index < sizeof(value->flags)){
        if (tcp->fin){
            value->flags[index] = 'F';
            index++;
        }
    }

    // if (index < sizeof(value->flags)){
    //     if (tcp->rst){
    //         value->flags[index] = 'R';
    //         index++;
    //     }
    // }

    bpf_printk("Flags: %d", tcp->syn);

    value->index=index;
}

Dumping out compiled code it looks like this:

0000000000000550 LBB1_7:
;     __u8 index = value->index;
     170:       61 61 00 00 00 00 00 00 r1 = *(u32 *)(r6 + 0)
;     if (index >= sizeof(value->flags)){
     171:       57 01 00 00 ff 00 00 00 r1 &= 255
     172:       25 01 33 00 0f 00 00 00 if r1 > 15 goto +51 <LBB1_17>
;         if (tcp->syn){
     173:       69 72 2e 00 00 00 00 00 r2 = *(u16 *)(r7 + 46)
     174:       57 02 00 00 00 02 00 00 r2 &= 512
     175:       15 02 05 00 00 00 00 00 if r2 == 0 goto +5 <LBB1_10>
;             value->flags[index] = 'S';
     176:       bf 62 00 00 00 00 00 00 r2 = r6
     177:       0f 12 00 00 00 00 00 00 r2 += r1
     178:       b7 03 00 00 53 00 00 00 r3 = 83
     179:       73 32 04 00 00 00 00 00 *(u8 *)(r2 + 4) = r3
;             index++;
     180:       07 01 00 00 01 00 00 00 r1 += 1

00000000000005a8 LBB1_10:
;     if (index < sizeof(value->flags)){
     181:       bf 13 00 00 00 00 00 00 r3 = r1
     182:       57 03 00 00 ff 00 00 00 r3 &= 255
     183:       bf 18 00 00 00 00 00 00 r8 = r1
     184:       25 03 19 00 0f 00 00 00 if r3 > 15 goto +25 <LBB1_16>
;         if (tcp->fin){
     185:       69 72 2e 00 00 00 00 00 r2 = *(u16 *)(r7 + 46)
     186:       bf 24 00 00 00 00 00 00 r4 = r2
     187:       57 04 00 00 00 01 00 00 r4 &= 256
     188:       bf 18 00 00 00 00 00 00 r8 = r1
     189:       15 04 0b 00 00 00 00 00 if r4 == 0 goto +11 <LBB1_14>
;             value->flags[index] = 'F';
     190:       bf 62 00 00 00 00 00 00 r2 = r6
     191:       0f 32 00 00 00 00 00 00 r2 += r3
     192:       b7 03 00 00 46 00 00 00 r3 = 70
     193:       73 32 04 00 00 00 00 00 *(u8 *)(r2 + 4) = r3
     194:       b7 08 00 00 10 00 00 00 r8 = 16
;     if (index < sizeof(value->flags)){
     195:       bf 12 00 00 00 00 00 00 r2 = r1
     196:       57 02 00 00 ff 00 00 00 r2 &= 255
     197:       25 02 0c 00 0e 00 00 00 if r2 > 14 goto +12 <LBB1_16>
;         if (tcp->rst){
     198:       69 72 2e 00 00 00 00 00 r2 = *(u16 *)(r7 + 46)
;             index++;
     199:       07 01 00 00 01 00 00 00 r1 += 1
     200:       bf 18 00 00 00 00 00 00 r8 = r1

0000000000000648 LBB1_14:
;         if (tcp->rst){
     201:       57 02 00 00 00 04 00 00 r2 &= 1024
     202:       15 02 07 00 00 00 00 00 if r2 == 0 goto +7 <LBB1_16>
;     if (index < sizeof(value->flags)){
     203:       bf 81 00 00 00 00 00 00 r1 = r8
     204:       57 01 00 00 ff 00 00 00 r1 &= 255
;             value->flags[index] = 'R';
     205:       bf 62 00 00 00 00 00 00 r2 = r6
     206:       0f 12 00 00 00 00 00 00 r2 += r1
     207:       b7 01 00 00 52 00 00 00 r1 = 82
     208:       73 12 04 00 00 00 00 00 *(u8 *)(r2 + 4) = r1
;             index++;
     209:       07 08 00 00 01 00 00 00 r8 += 1

0000000000000690 LBB1_16:
     210:       b7 01 00 00 64 00 00 00 r1 = 100
;     bpf_printk("Flags: %d", tcp->syn);
     211:       6b 1a f0 ff 00 00 00 00 *(u16 *)(r10 - 16) = r1
     212:       18 01 00 00 46 6c 61 67 00 00 00 00 73 3a 20 25 r1 = 2675202445988162630 ll
     214:       7b 1a e8 ff 00 00 00 00 *(u64 *)(r10 - 24) = r1
     215:       69 73 2e 00 00 00 00 00 r3 = *(u16 *)(r7 + 46)
     216:       77 03 00 00 09 00 00 00 r3 >>= 9
     217:       57 03 00 00 01 00 00 00 r3 &= 1
     218:       bf a1 00 00 00 00 00 00 r1 = r10
     219:       07 01 00 00 e8 ff ff ff r1 += -24
     220:       b7 02 00 00 0a 00 00 00 r2 = 10
     221:       85 00 00 00 06 00 00 00 call 6
;     value->index=index;
     222:       57 08 00 00 ff 00 00 00 r8 &= 255
     223:       63 86 00 00 00 00 00 00 *(u32 *)(r6 + 0) = r8

Seems like in the compiled code for tcp->rst, index < sizeof(value->flags) is checked twice but the second time there is no goto statement, and perhaps that's why the verifiers believes that we are accessing an unchecked memory address? Does anyone know why and how to fix this?

Edit: As mentioned by Barmar, the if statement was simply reordered by the compiler and the error is the same as the previous question. In the check for tcp->rst, index was initially in r2 and was checked to be within bound. However, when accessing tcp->flags[index], index is now in r1 (hence the verifier lost the context that index was bound-check before and throw this error). However, I'm still lost as to how to fix this since this does not happen to tcp->syn or tcp->fin.

0

There are 0 best solutions below