首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >xdp运行中寄存器R2 offset is outside of the packet?

xdp运行中寄存器R2 offset is outside of the packet?

提问于 2024-07-09 22:38:17
回答 0关注 0查看 51

我开始用ebpf和XDP编写代码。我正在使用python bcc将XDP程序加载到端口上,想使用xdp提取传输层udp协议上层中dns协议的发送数据中的查询域名。代码如下:

代码语言:c
复制

#include <uapi/linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_vlan.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/ipv6.h>
// BPF_TABLE(MAPTYPE, uint32_t, long, dropcnt, 256);
#define ETH_HLEN 14
#define UDP_HLEN 8
#define TLS2_PRE_LEN 43
#define DNS_HD_LEN 12
int xdp_prog1(struct xdp_md *ctx) {
    void* data_end = (void*)(long)ctx->data_end;
    void* data = (void*)(long)ctx->data;
    char sni[64]="";
    struct ethhdr *eth = data;
    // drop packets
    int rc = XDP_PASS; // let pass XDP_PASS or redirect to tx via XDP_TX
    long *value;
    uint16_t h_proto;
    uint8_t iph_proto;
    uint64_t nh_off = 0;
    uint32_t index;
    nh_off = sizeof(*eth);
    if (data + nh_off  > data_end)
        return rc;
    h_proto = eth->h_proto;
    // parse double vlans
    if (h_proto != htons(ETH_P_IP)){
        return rc;
    }
    else{
        //bpf_trace_printk("in ip\\n");
        struct iphdr *iph = data + nh_off;
        nh_off += sizeof(*iph);
        if (data + nh_off  > data_end)
            return rc;
        if (iph->protocol != IPPROTO_UDP)
            return rc;
        bpf_trace_printk("in udp\\n");
        struct udphdr *udph = data + nh_off;
        nh_off += sizeof(*udph);
        if (data + nh_off  > data_end)
            return rc;
        if (htons(udph->dest) == 53){
            bpf_trace_printk("in dns\\n");
            int payload_length = htons(udph->len) - UDP_HLEN;
            int server_name_len = payload_length - DNS_HD_LEN - 4;
            if (server_name_len<=0){
                return rc;
            }
            unsigned int len = payload_length - DNS_HD_LEN - 4;
            unsigned int server_name_offset = nh_off + DNS_HD_LEN;
            void *data_need = data+server_name_offset+len;
            if ( data_need > data_end){
                return rc;
            }
            //char *to_ptr = (char *)bpf_map_alloc_skb_bytes(ctx, len, 0);
            //if (!to_ptr) {
            //     return XDP_DROP; // 分配内存失败则丢弃数据包
            //}
            char *data_off = (char *)data+server_name_offset;
            //bpf_skb_store_bytes(ctx, 0, data_off, len, 0);
            char c;
            for(unsigned char i = 0;i<len &&i<64;i++){
                if((void *)&data_off[i]>data_end){
                    break;
                }
                c = *(data_off+i);
                sni[i] = c;
            }  
            bpf_trace_printk("in done %d\\n", c);
            //bpf_map_free_skb_bytes(ctx, to_ptr, 0);
        }
        else{
            return rc;
        }
        bpf_trace_printk("udp captured  ip port: %d, %d\\n", htons(udph->source),htons(udph->dest));
    }
    return rc;
}

使用的思路如下,首先分析完udp层的数据,使用udp中字段的length长度减去udp头的长度得到载荷的大小,然后根据dns查询数据包的结构计算出域名的大小以及偏移off位置,最后使用循环读取域名所在的地址值。

但是在读取数据过程中出现了验证器未能通过的现象,但是我在过程对于值的情况是进行了安全检查的。。。

验证器提供的信息如下:

代码语言:txt
复制
; void* data_end = (void*)(long)ctx->data_end;
0: (61) r7 = *(u32 *)(r1 +4)
; void* data = (void*)(long)ctx->data;
1: (61) r6 = *(u32 *)(r1 +0)
; if (data + nh_off  > data_end)
2: (bf) r1 = r6
3: (07) r1 += 14
; if (data + nh_off  > data_end)
4: (2d) if r1 > r7 goto pc+86
 R1_w=pkt(id=0,off=14,r=14,imm=0) R6_w=pkt(id=0,off=0,r=14,imm=0) R7_w=pkt_end(id=0,off=0,imm=0) R10=fp0
5: (bf) r1 = r6
6: (07) r1 += 34
; if (h_proto != htons(ETH_P_IP)){
7: (2d) if r1 > r7 goto pc+83
 R1_w=pkt(id=0,off=34,r=34,imm=0) R6_w=pkt(id=0,off=0,r=34,imm=0) R7_w=pkt_end(id=0,off=0,imm=0) R10=fp0
8: (71) r1 = *(u8 *)(r6 +13)
9: (67) r1 <<= 8
10: (71) r2 = *(u8 *)(r6 +12)
11: (4f) r1 |= r2
12: (57) r1 &= 65535
13: (55) if r1 != 0x8 goto pc+77
 R1=inv8 R2=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6=pkt(id=0,off=0,r=34,imm=0) R7=pkt_end(id=0,off=0,imm=0) R10=fp0
; if (iph->protocol != IPPROTO_UDP)
14: (71) r1 = *(u8 *)(r6 +23)
; if (iph->protocol != IPPROTO_UDP)
15: (55) if r1 != 0x11 goto pc+75
 R1_w=inv17 R2=inv(id=0,umax_value=255,var_off=(0x0; 0xff)) R6=pkt(id=0,off=0,r=34,imm=0) R7=pkt_end(id=0,off=0,imm=0) R10=fp0
16: (18) r1 = 0xa706475206e69
; ({ char _fmt[] = "in udp\n"; bpf_trace_printk_(_fmt, sizeof(_fmt)); });
18: (7b) *(u64 *)(r10 -32) = r1
19: (bf) r1 = r10
; 
20: (07) r1 += -32
; ({ char _fmt[] = "in udp\n"; bpf_trace_printk_(_fmt, sizeof(_fmt)); });
21: (b7) r2 = 8
22: (85) call bpf_trace_printk#6
last_idx 22 first_idx 13
regs=4 stack=0 before 21: (b7) r2 = 8
; if (data + nh_off  > data_end)
23: (bf) r8 = r6
24: (07) r8 += 42
; if (data + nh_off  > data_end)
25: (2d) if r8 > r7 goto pc+65
 R0=inv(id=0) R6=pkt(id=0,off=0,r=42,imm=0) R7=pkt_end(id=0,off=0,imm=0) R8_w=pkt(id=0,off=42,r=42,imm=0) R10=fp0 fp-32=mmmmmmmm
; if (htons(udph->dest) == 53){
26: (69) r1 = *(u16 *)(r6 +36)
; if (htons(udph->dest) == 53){
27: (55) if r1 != 0x3500 goto pc+63
 R0=inv(id=0) R1_w=inv13568 R6=pkt(id=0,off=0,r=42,imm=0) R7=pkt_end(id=0,off=0,imm=0) R8_w=pkt(id=0,off=42,r=42,imm=0) R10=fp0 fp-32=mmmmmmmm
28: (18) r1 = 0xa736e64206e69
; ({ char _fmt[] = "in dns\n"; bpf_trace_printk_(_fmt, sizeof(_fmt)); });
30: (7b) *(u64 *)(r10 -32) = r1
31: (bf) r1 = r10
; 
32: (07) r1 += -32
; ({ char _fmt[] = "in dns\n"; bpf_trace_printk_(_fmt, sizeof(_fmt)); });
33: (b7) r2 = 8
34: (85) call bpf_trace_printk#6
last_idx 34 first_idx 23
regs=4 stack=0 before 33: (b7) r2 = 8
; int payload_length = htons(udph->len) - UDP_HLEN;
35: (69) r1 = *(u16 *)(r6 +38)
36: (dc) r1 = be16 r1
37: (b7) r2 = 25
; if ( data_need > data_end){
38: (2d) if r2 > r1 goto pc+52
 R0=inv(id=0) R1_w=inv(id=0,umin_value=25) R2_w=inv25 R6=pkt(id=0,off=0,r=42,imm=0) R7=pkt_end(id=0,off=0,imm=0) R8=pkt(id=0,off=42,r=42,imm=0) R10=fp0 fp-32=mmmmmmmm
; 
39: (bf) r2 = r1
40: (07) r2 += -8
41: (67) r2 <<= 32
42: (77) r2 >>= 32
43: (0f) r8 += r2
last_idx 43 first_idx 35
regs=4 stack=0 before 42: (77) r2 >>= 32
regs=4 stack=0 before 41: (67) r2 <<= 32
regs=4 stack=0 before 40: (07) r2 += -8
regs=4 stack=0 before 39: (bf) r2 = r1
regs=2 stack=0 before 38: (2d) if r2 > r1 goto pc+52
regs=6 stack=0 before 37: (b7) r2 = 25
regs=2 stack=0 before 36: (dc) r1 = be16 r1
regs=2 stack=0 before 35: (69) r1 = *(u16 *)(r6 +38)
; if ( data_need > data_end){
44: (2d) if r8 > r7 goto pc+46
 R0=inv(id=0) R1_w=inv(id=1,umin_value=25) R2_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R6=pkt(id=0,off=0,r=42,imm=0) R7=pkt_end(id=0,off=0,imm=0) R8_w=pkt(id=2,off=42,r=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R10=fp0 fp-32=mmmmmmmm
; for(unsigned char i = 0;i<len &&i<64;i++){
45: (07) r1 += -25
46: (bf) r2 = r1
47: (67) r2 <<= 32
48: (77) r2 >>= 32
49: (b7) r3 = 63
50: (2d) if r3 > r2 goto pc+1
 R0=inv(id=0) R1=inv(id=3) R2=inv(id=0,umin_value=63,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R3=inv63 R6=pkt(id=0,off=0,r=42,imm=0) R7=pkt_end(id=0,off=0,imm=0) R8=pkt(id=2,off=42,r=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R10=fp0 fp-32=mmmmmmmm
51: (b7) r1 = 63
; c = *(data_off+i);
52: (67) r1 <<= 32
53: (77) r1 >>= 32
; char *data_off = (char *)data+server_name_offset;
54: (bf) r2 = r6
55: (0f) r2 += r1
last_idx 55 first_idx 50
regs=2 stack=0 before 54: (bf) r2 = r6
regs=2 stack=0 before 53: (77) r1 >>= 32
regs=2 stack=0 before 52: (67) r1 <<= 32
regs=2 stack=0 before 51: (b7) r1 = 63
; c = *(data_off+i);
56: (71) r3 = *(u8 *)(r2 +54)
invalid access to packet, off=117 size=1, R2(id=0,off=117,r=42)
R2 offset is outside of the packet

回答

和开发者交流更多问题细节吧,去 写回答
相关文章

相似问题

相关问答用户
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档