我有这个XDP程序来解析DNS数据包以获取查询域名并在bpf映射中查找域名。 https://github.com/vincentmli/xdp-tools/blob/dns-deny/xdp-dns/xdp_dns.bpf.c。我收到以下验证错误:
xdp-loader load -vvv -m skb lo xdp-dns/xdp_dns.bpf.o
libbpf: prog 'xdp_dns': -- BEGIN PROG LOAD LOG --
Validating xdp_dns() func#0...
0: R1=ctx(off=0,imm=0) R10=fp0
; int xdp_dns(struct xdp_md *ctx)
0: (bf) r6 = r1 ; R1=ctx(off=0,imm=0) R6_w=ctx(off=0,imm=0)
; if (bpf_xdp_adjust_meta(ctx, -(int)sizeof(struct meta_data)))
1: (18) r2 = 0xfffffff8 ; R2_w=4294967288
3: (85) call bpf_xdp_adjust_meta#54 ; R0_w=scalar()
4: (bf) r1 = r0 ; R0_w=scalar(id=1) R1_w=scalar(id=1)
5: (b7) r0 = 2 ; R0_w=2
; if (bpf_xdp_adjust_meta(ctx, -(int)sizeof(struct meta_data)))
6: (55) if r1 != 0x0 goto pc+81 ; R1_w=0
; c->end = (void *)(long)ctx->data_end;
7: (61) r2 = *(u32 *)(r6 +4) ; R2_w=pkt_end(off=0,imm=0) R6_w=ctx(off=0,imm=0)
; c->end = (void *)(long)ctx->data_end;
8: (7b) *(u64 *)(r10 -8) = r2 ; R2_w=pkt_end(off=0,imm=0) R10=fp0 fp-8_w=pkt_end
; c->pos = (void *)(long)ctx->data;
9: (61) r4 = *(u32 *)(r6 +0) ; R4_w=pkt(off=0,r=0,imm=0) R6_w=ctx(off=0,imm=0)
; md = (void *)(long)ctx->data_meta;
10: (61) r3 = *(u32 *)(r6 +8) ; R3_w=pkt_meta(off=0,r=0,imm=0) R6_w=ctx(off=0,imm=0)
; if ((void *)(md + 1) > c.pos)
11: (bf) r1 = r3 ; R1_w=pkt_meta(off=0,r=0,imm=0) R3_w=pkt_meta(off=0,r=0,imm=0)
12: (07) r1 += 8 ; R1=pkt_meta(off=8,r=0,imm=0)
; if ((void *)(md + 1) > c.pos)
13: (2d) if r1 > r4 goto pc+74 ; R1=pkt_meta(off=8,r=8,imm=0) R4=pkt(off=0,r=0,imm=0)
; PARSE_FUNC_DECLARATION(ethhdr)
14: (bf) r1 = r4 ; R1_w=pkt(off=0,r=0,imm=0) R4=pkt(off=0,r=0,imm=0)
15: (07) r1 += 14 ; R1_w=pkt(off=14,r=0,imm=0)
; PARSE_FUNC_DECLARATION(ethhdr)
16: (2d) if r1 > r2 goto pc+71 ; R1_w=pkt(off=14,r=14,imm=0) R2=pkt_end(off=0,imm=0)
17: (15) if r4 == 0x0 goto pc+70 ; R4=pkt(off=0,r=14,imm=0)
; *eth_proto = eth->h_proto;
18: (71) r0 = *(u8 *)(r4 +12) ; R0_w=scalar(umax=255,var_off=(0x0; 0xff)) R4=pkt(off=0,r=14,imm=0)
19: (71) r5 = *(u8 *)(r4 +13) ; R4=pkt(off=0,r=14,imm=0) R5_w=scalar(umax=255,var_off=(0x0; 0xff))
20: (67) r5 <<= 8 ; R5_w=scalar(umax=65280,var_off=(0x0; 0xff00))
21: (4f) r5 |= r0 ; R0_w=scalar(umax=255,var_off=(0x0; 0xff)) R5_w=scalar()
; *eth_proto = eth->h_proto;
22: (6b) *(u16 *)(r3 +0) = r5 ; R3=pkt_meta(off=0,r=8,imm=0) R5=scalar()
; || *eth_proto == __bpf_htons(ETH_P_8021AD)) {
23: (15) if r5 == 0xa888 goto pc+1 ; R5=scalar()
24: (55) if r5 != 0x81 goto pc+16 ; R5=129
; PARSE_FUNC_DECLARATION(vlanhdr)
25: (bf) r6 = r4 ; R4=pkt(off=0,r=14,imm=0) R6_w=pkt(off=0,r=14,imm=0)
26: (07) r6 += 18 ; R6_w=pkt(off=18,r=14,imm=0)
27: (b7) r0 = 2 ; R0_w=2
; PARSE_FUNC_DECLARATION(vlanhdr)
28: (2d) if r6 > r2 goto pc+59 ; R2=pkt_end(off=0,imm=0) R6_w=pkt(off=18,r=18,imm=0)
29: (15) if r1 == 0x0 goto pc+58 ; R1=pkt(off=14,r=18,imm=0)
; *eth_proto = vlan->encap_proto;
30: (69) r5 = *(u16 *)(r4 +16) ; R4=pkt(off=0,r=18,imm=0) R5_w=scalar(umax=65535,var_off=(0x0; 0xffff))
; *eth_proto = vlan->encap_proto;
31: (6b) *(u16 *)(r3 +0) = r5 ; R3=pkt_meta(off=0,r=8,imm=0) R5=scalar(umax=65535,var_off=(0x0; 0xffff))
; || *eth_proto == __bpf_htons(ETH_P_8021AD)) {
32: (15) if r5 == 0xa888 goto pc+2 ; R5=scalar(umax=65535,var_off=(0x0; 0xffff))
33: (bf) r1 = r6 ; R1_w=pkt(off=18,r=18,imm=0) R6=pkt(off=18,r=18,imm=0)
34: (55) if r5 != 0x81 goto pc+6 ; R5=129
; PARSE_FUNC_DECLARATION(vlanhdr)
35: (bf) r1 = r4 ; R1_w=pkt(off=0,r=18,imm=0) R4=pkt(off=0,r=18,imm=0)
36: (07) r1 += 22 ; R1_w=pkt(off=22,r=18,imm=0)
; PARSE_FUNC_DECLARATION(vlanhdr)
37: (2d) if r1 > r2 goto pc+50 ; R1_w=pkt(off=22,r=22,imm=0) R2=pkt_end(off=0,imm=0)
38: (15) if r6 == 0x0 goto pc+49 ; R6=pkt(off=18,r=22,imm=0)
; *eth_proto = vlan->encap_proto;
39: (69) r5 = *(u16 *)(r4 +20) ; R4=pkt(off=0,r=22,imm=0) R5_w=scalar(umax=65535,var_off=(0x0; 0xffff))
; *eth_proto = vlan->encap_proto;
40: (6b) *(u16 *)(r3 +0) = r5 ; R3=pkt_meta(off=0,r=8,imm=0) R5=scalar(umax=65535,var_off=(0x0; 0xffff))
; md->ip_pos = c.pos - (void *)eth;
41: (bf) r0 = r1 ; R0_w=pkt(off=22,r=22,imm=0) R1=pkt(off=22,r=22,imm=0)
42: (1f) r0 -= r4 ; R0_w=scalar() R4=pkt(off=0,r=22,imm=0)
; md->ip_pos = c.pos - (void *)eth;
43: (6b) *(u16 *)(r3 +2) = r0 ; R0_w=scalar() R3=pkt_meta(off=0,r=8,imm=0)
; if (md->eth_proto == __bpf_htons(ETH_P_IP)) {
44: (55) if r5 != 0x8 goto pc+42 ; R5=8
; PARSE_FUNC_DECLARATION(iphdr)
45: (bf) r4 = r1 ; R1=pkt(off=22,r=22,imm=0) R4_w=pkt(off=22,r=22,imm=0)
46: (07) r4 += 20 ; R4_w=pkt(off=42,r=22,imm=0)
47: (b7) r0 = 2 ; R0_w=2
; PARSE_FUNC_DECLARATION(iphdr)
48: (2d) if r4 > r2 goto pc+39 ; R2=pkt_end(off=0,imm=0) R4_w=pkt(off=42,r=42,imm=0)
49: (15) if r1 == 0x0 goto pc+38 ; R1=pkt(off=22,r=42,imm=0)
; switch (ipv4->protocol) {
50: (71) r3 = *(u8 *)(r1 +9) ; R1=pkt(off=22,r=42,imm=0) R3_w=scalar(umax=255,var_off=(0x0; 0xff))
; switch (ipv4->protocol) {
51: (55) if r3 != 0x11 goto pc+35 ; R3_w=17
; PARSE_FUNC_DECLARATION(udphdr)
52: (bf) r3 = r1 ; R1=pkt(off=22,r=42,imm=0) R3_w=pkt(off=22,r=42,imm=0)
53: (07) r3 += 28 ; R3_w=pkt(off=50,r=42,imm=0)
; PARSE_FUNC_DECLARATION(udphdr)
54: (2d) if r3 > r2 goto pc+33 ; R2=pkt_end(off=0,imm=0) R3_w=pkt(off=50,r=50,imm=0)
55: (15) if r4 == 0x0 goto pc+32 ; R4=pkt(off=42,r=50,imm=0)
; || !(udp->dest == __bpf_htons(DNS_PORT))
56: (69) r4 = *(u16 *)(r1 +22) ; R1=pkt(off=22,r=50,imm=0) R4=scalar(umax=65535,var_off=(0x0; 0xffff))
; || !(dns = parse_dnshdr(&c)))
57: (55) if r4 != 0x3500 goto pc+30 ; R4=13568
; PARSE_FUNC_DECLARATION(dnshdr)
58: (bf) r4 = r1 ; R1=pkt(off=22,r=50,imm=0) R4_w=pkt(off=22,r=50,imm=0)
59: (07) r4 += 40 ; R4_w=pkt(off=62,r=50,imm=0)
; PARSE_FUNC_DECLARATION(dnshdr)
60: (2d) if r4 > r2 goto pc+27 ; R2=pkt_end(off=0,imm=0) R4_w=pkt(off=62,r=62,imm=0)
61: (7b) *(u64 *)(r10 -16) = r4 ; R4_w=pkt(off=62,r=62,imm=0) R10=fp0 fp-16_w=pkt
; if (!(udp = parse_udphdr(&c))
62: (15) if r3 == 0x0 goto pc+25 ; R3=pkt(off=50,r=62,imm=0)
63: (b7) r0 = 0 ; R0_w=0
; if (dns->flags.as_bits_and_pieces.qr
64: (69) r2 = *(u16 *)(r1 +30) ; R1=pkt(off=22,r=62,imm=0) R2_w=scalar(umax=65535,var_off=(0x0; 0xffff))
; if (dns->flags.as_bits_and_pieces.qr
65: (57) r2 &= 128 ; R2=scalar(umax=128,var_off=(0x0; 0x80))
; || dns->qdcount != __bpf_htons(1)
66: (55) if r2 != 0x0 goto pc+21 ; R2=0
; || dns->qdcount != __bpf_htons(1)
67: (69) r2 = *(u16 *)(r1 +32) ; R1=pkt(off=22,r=62,imm=0) R2_w=scalar(umax=65535,var_off=(0x0; 0xffff))
; || dns->ancount || dns->nscount
68: (55) if r2 != 0x100 goto pc+19 ; R2_w=256
; || dns->ancount || dns->nscount
69: (69) r2 = *(u16 *)(r1 +34) ; R1=pkt(off=22,r=62,imm=0) R2_w=scalar(umax=65535,var_off=(0x0; 0xffff))
; || dns->ancount || dns->nscount
70: (55) if r2 != 0x0 goto pc+17 ; R2_w=0
; || dns->ancount || dns->nscount
71: (69) r2 = *(u16 *)(r1 +36) ; R1=pkt(off=22,r=62,imm=0) R2_w=scalar(umax=65535,var_off=(0x0; 0xffff))
; || dns->arcount > __bpf_htons(2))
72: (55) if r2 != 0x0 goto pc+15 ; R2_w=0
; || dns->arcount > __bpf_htons(2))
73: (69) r1 = *(u16 *)(r1 +38) ; R1=scalar(umax=65535,var_off=(0x0; 0xffff))
; if (dns->flags.as_bits_and_pieces.qr
74: (25) if r1 > 0x200 goto pc+13 ; R1=scalar(umax=512,var_off=(0x0; 0x3ff))
75: (bf) r1 = r10 ; R1_w=fp0 R10=fp0
; qname = parse_dname(&c);
76: (07) r1 += -16 ; R1_w=fp-16
77: (85) call pc+11
reg type unsupported for arg#0 function parse_dname#26
caller:
R6=pkt(off=18,r=62,imm=0) R10=fp0 fp-8=pkt_end fp-16=pkt
callee:
frame1: R1_w=fp-16 R2=0 R3=pkt(off=50,r=62,imm=0) R4=pkt(off=62,r=62,imm=0) R5=8 R10=fp0
; char *parse_dname(struct cursor *c)
89: (b7) r3 = 0 ; frame1: R3_w=0
90: (79) r4 = *(u64 *)(r1 +8) ; frame1: R1_w=fp-16 R4_w=pkt_end(off=0,imm=0)
; __u8 *dname = c->pos;
91: (79) r2 = *(u64 *)(r1 +0) ; frame1: R1_w=fp-16 R2_w=pkt(off=62,r=62,imm=0)
92: (18) r6 = 0x100000000000000 ; frame1: R6_w=72057594037927936
94: (bf) r5 = r2 ; frame1: R2_w=pkt(off=62,r=62,imm=0) R5_w=pkt(off=62,r=62,imm=0)
95: (05) goto pc+5
; if (c->pos + 1 > c->end)
101: (bf) r7 = r5 ; frame1: R5=pkt(off=62,r=62,imm=0) R7_w=pkt(off=62,r=62,imm=0)
102: (07) r7 += 1 ; frame1: R7_w=pkt(off=63,r=62,imm=0)
103: (b7) r0 = 0 ; frame1: R0_w=0
; if (c->pos + 1 > c->end)
104: (2d) if r7 > r4 goto pc+21 ; frame1: R4=pkt_end(off=0,imm=0) R7_w=pkt(off=63,r=63,imm=0)
; if ((o & 0xC0) == 0xC0) {
105: (71) r7 = *(u8 *)(r5 +0) ; frame1: R5=pkt(off=62,r=63,imm=0) R7_w=scalar(umax=255,var_off=(0x0; 0xff))
; if ((o & 0xC0) == 0xC0) {
106: (bf) r0 = r7 ; frame1: R0_w=scalar(id=2,umax=255,var_off=(0x0; 0xff)) R7_w=scalar(id=2,umax=255,var_off=(0x0; 0xff))
107: (57) r0 &= 192 ; frame1: R0_w=scalar(umax=192,var_off=(0x0; 0xc0))
; if ((o & 0xC0) == 0xC0) {
108: (55) if r0 != 0xc0 goto pc+4 ; frame1: R0_w=192
; c->pos += 2;
109: (07) r5 += 2 ; frame1: R5_w=pkt(off=64,r=63,imm=0)
110: (7b) *(u64 *)(r1 +0) = r5 ; frame1: R1=fp-16 R5_w=pkt(off=64,r=63,imm=0)
111: (bf) r0 = r2 ; frame1: R0_w=pkt(off=62,r=63,imm=0) R2=pkt(off=62,r=63,imm=0)
112: (05) goto pc+13
; }
126: (95) exit
returning from callee:
frame1: R0=pkt(off=62,r=63,imm=0) R1=fp-16 R2=pkt(off=62,r=63,imm=0) R3=0 R4=pkt_end(off=0,imm=0) R5=pkt(off=64,r=63,imm=0) R6=72057594037927936 R7=scalar(id=2,umax=255,var_off=(0x0; 0xff)) R10=fp0
to caller at 78:
R0=pkt(off=62,r=63,imm=0) R6=pkt(off=18,r=63,imm=0) R10=fp0 fp-8=pkt_end fp-16=pkt
; qname = parse_dname(&c);
78: (bf) r2 = r0 ; R0=pkt(off=62,r=63,imm=0) R2_w=pkt(off=62,r=63,imm=0)
79: (b7) r0 = 0 ; R0_w=0
; if (!qname) {
80: (15) if r2 == 0x0 goto pc+7 ; R2_w=pkt(off=62,r=63,imm=0)
; if (bpf_map_lookup_elem(&domain_denylist, qname))
81: (18) r1 = 0xffff93604d4c2400 ; R1_w=map_ptr(off=0,ks=254,vs=1,imm=0)
83: (85) call bpf_map_lookup_elem#1
invalid access to packet, off=62 size=254, R2(id=0,off=62,r=63)
R2 offset is outside of the packet
processed 101 insns (limit 1000000) max_states_per_insn 0 total_states 10 peak_states 10 mark_read 8
-- END PROG LOAD LOG --
libbpf: prog 'xdp_dns': failed to load: -13
libbpf: failed to load object 'xdp-dns/xdp_dns.bpf.o'
libxdp: Failed to load program xdp_dns: Permission denied
Couldn't attach XDP program on iface 'lo': Permission denied(-13)
有类似的问题问XDP程序无法加载并出现错误“R7偏移量在数据包之外”需要帮助,不完全理解问题,我添加了如下检查:
diff --git a/xdp-dns/xdp_dns.bpf.c b/xdp-dns/xdp_dns.bpf.c
index 01ab2b6..d6d8703 100644
--- a/xdp-dns/xdp_dns.bpf.c
+++ b/xdp-dns/xdp_dns.bpf.c
@@ -198,9 +198,9 @@ int xdp_dns(struct xdp_md *ctx)
return XDP_ABORTED; // Return FORMERR?
}
- // avoid R2 offset is outside of the packet error
- //if (qname + MAX_DOMAIN_SIZE + 1 > c.end)
- // return XDP_ABORTED; // Return FORMERR?
+ //avoid R2 offset is outside of the packet error
+ if (qname + MAX_DOMAIN_SIZE + 1 > c.end)
+ return XDP_ABORTED; // Return FORMERR?
此更改通过了验证程序,XDP 程序加载正常,但是当我测试发送 DNS 查询时,
if (qname + MAX_DOMAIN_SIZE + 1 > c.end)
始终为 true,导致 DNS 数据包被 return XDP_ABORTED
丢弃。我想我在 bpf 映射查找之前没有正确添加数据包绑定检查,有任何线索吗?
从验证者错误开始
; if (!qname) {
80: (15) if r2 == 0x0 goto pc+7 ; R2_w=pkt(off=62,r=63,imm=0)
; if (bpf_map_lookup_elem(&domain_denylist, qname))
81: (18) r1 = 0xffff93604d4c2400 ; R1_w=map_ptr(off=0,ks=254,vs=1,imm=0)
83: (85) call bpf_map_lookup_elem#1
invalid access to packet, off=62 size=254, R2(id=0,off=62,r=63)
我会翻译相关部分:
R2_w=pkt(off=62,r=63,imm=0)
- 寄存器 2 指向偏移量 62 处的数据包,并且您已检查最多 63 的边界,因此您可以安全地访问 1 字节的数据。R1_w=map_ptr(off=0,ks=254,vs=1,imm=0)
- 寄存器 1 是一个指向映射的指针,其键大小为 254 字节,值大小为 1 字节call bpf_map_lookup_elem
- 调用地图查找助手,其中 R1 是指向地图的指针,R2 是地图的值。bpf_map_lookup_elem
期望能够从 R2 读取 254 个字节,但您没有对这个数量进行边界检查。这就是截取的代码的作用
if (qname + MAX_DOMAIN_SIZE + 1 > c.end)
return XDP_ABORTED;
它断言数据包中偏移量 62 之后必须至少有 254 字节。因此,如果遇到小于 316 字节的数据包,程序将中止。这满足了验证者的要求,因为当数据包较大时,它可以读取所有 254 个字节并与地图进行比较。
您可能想要做的是记录
parse_dname
返回的域名长度并用它来执行边界检查。然后准备一个 MAX_DOMAIN_SIZE
字节的清零缓冲区,并将域名复制到缓冲区中,直到域名的长度。您最终应该得到一个与映射键大小相同的缓冲区,并用零填充。您可以使用缓冲区进行查找。