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.