ebpf XDP 程序 R2 偏移量位于数据包之外

问题描述 投票:0回答:1

我有这个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 映射查找之前没有正确添加数据包绑定检查,有任何线索吗?

dns ebpf xdp-bpf
1个回答
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_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
字节的清零缓冲区,并将域名复制到缓冲区中,直到域名的长度。您最终应该得到一个与映射键大小相同的缓冲区,并用零填充。您可以使用缓冲区进行查找。

© www.soinside.com 2019 - 2024. All rights reserved.