即使在访问数据包中的字节之前我正在执行检查,我invalid access to packet
还是从 eBPF 验证程序中获取信息。偏移量存储在BPF_MAP_TYPE_ARRAY
. 循环迭代的次数无关紧要,因为即使我进行一次迭代也会发生这个问题。
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
struct packet_context {
__u16 pkt_offset;
};
struct bpf_map_def SEC("maps") context_table = {
.type = BPF_MAP_TYPE_ARRAY,
.key_size = sizeof(__u32),
.value_size = sizeof(struct packet_context),
.max_entries = 1,
};
SEC("xdp")
int collect_ips_prog(struct xdp_md *ctx) {
char *data_end = (char *)(long)ctx->data_end;
char *data = (char *)(long)ctx->data;
__u32 index = 0;
struct packet_context *pkt_ctx = (struct packet_context *) bpf_map_lookup_elem(&context_table, &index);
if (pkt_ctx == NULL) {
goto end;
}
__u32 length = 0;
for (__u16 j = 0; j < 253; j++) {
if (data_end < data + pkt_ctx->pkt_offset + j + 1) {
goto end;
}
if (data[pkt_ctx->pkt_offset + j] == '\r') {
break;
}
length++;
}
bpf_printk("%d", length);
end:
return XDP_PASS;
}
这是错误。错误发生在if (data[pkt_ctx->pkt_offset + j] == '\r') {
j = 0 时。
0: (61) r7 = *(u32 *)(r1 +0)
; char *data_end = (char *)(long)ctx->data_end;
1: (61) r8 = *(u32 *)(r1 +4)
2: (b7) r6 = 0
; __u32 index = 0;
3: (63) *(u32 *)(r10 -4) = r6
last_idx 3 first_idx 0
regs=40 stack=0 before 2: (b7) r6 = 0
4: (bf) r2 = r10
;
5: (07) r2 += -4
; struct packet_context *pkt_ctx = (struct packet_context *) bpf_map_lookup_elem(&context_table, &index);
6: (18) r1 = 0xffff9790029a2e00
8: (85) call bpf_map_lookup_elem#1
; if (pkt_ctx == NULL) {
9: (15) if r0 == 0x0 goto pc+22
R0_w=map_value(id=0,off=0,ks=4,vs=2,imm=0) R6_w=invP0 R7_w=pkt(id=0,off=0,r=0,imm=0) R8_w=pkt_end(id=0,off=0,imm=0) R10=fp0 fp-8=mmmm????
10: (69) r1 = *(u16 *)(r0 +0)
R0_w=map_value(id=0,off=0,ks=4,vs=2,imm=0) R6_w=invP0 R7_w=pkt(id=0,off=0,r=0,imm=0) R8_w=pkt_end(id=0,off=0,imm=0) R10=fp0 fp-8=mmmm????
; for (__u16 j = 0; j < 253; j++) {
11: (0f) r7 += r1
last_idx 11 first_idx 0
regs=2 stack=0 before 10: (69) r1 = *(u16 *)(r0 +0)
12: (b7) r3 = 253
; if (data_end < data + pkt_ctx->pkt_offset + j + 1) {
13: (bf) r1 = r7
14: (0f) r1 += r6
15: (bf) r2 = r1
16: (07) r2 += 1
; if (data_end < data + pkt_ctx->pkt_offset + j + 1) {
17: (2d) if r2 > r8 goto pc+14
R0=map_value(id=0,off=0,ks=4,vs=2,imm=0) R1_w=pkt(id=2,off=0,r=0,umax_value=65535,var_off=(0x0; 0xffff)) R2_w=pkt(id=2,off=1,r=0,umax_value=65535,var_off=(0x0; 0xffff)) R3=inv253 R6=invP0 R7=pkt(id=2,off=0,r=0,umax_value=65535,var_off=(0x0; 0xffff)) R8=pkt_end(id=0,off=0,imm=0) R10=fp0 fp-8=mmmm????
; if (data[pkt_ctx->pkt_offset + j] == '\r') {
18: (71) r1 = *(u8 *)(r1 +0)
invalid access to packet, off=0 size=1, R1(id=2,off=0,r=0)
R1 offset is outside of the packet
processed 18 insns (limit 1000000) max_states_per_insn 0 total_states 1 peak_states 1 mark_read 1
即使pkt_ctx->pkt_offset == 0xffff
,访问前的 if 条件也应该阻止访问数据包前 0xffff 字节之外的字节。