xdp-tutorial icon indicating copy to clipboard operation
xdp-tutorial copied to clipboard

call bpf_skb_store_bytes, but invalid mem access

Open dark520xiang opened this issue 3 years ago • 1 comments

last_idx 475 first_idx 448 regs=4 stack=0 before 474: (b7) r2 = 35 476: (bf) r7 = r10 477: (07) r7 += -96 478: (bf) r1 = r6 479: (b7) r2 = 42 480: (bf) r3 = r7 481: (b7) r4 = 14 482: (85) call bpf_skb_load_bytes#26 last_idx 482 first_idx 476 regs=10 stack=0 before 481: (b7) r4 = 14 483: (b7) r1 = 825307441 484: (63) *(u32 *)(r10 -96) = r1 485: (79) r2 = *(u64 *)(r10 -240) 486: (61) r1 = *(u32 *)(r2 +26) R2 invalid mem access 'inv' processed 450 insns (limit 1000000) max_states_per_insn 0 total_states 20 peak_states 20 mark_read 13

HINT: The invalid mem access 'inv' error can happen if you try to dereference memory without first using bpf_probe_read_kernel() to copy it to the BPF stack. Sometimes the bpf_probe_read_kernel() is automatic by the bcc rewriter, other times you'll need to be explicit.

Traceback (most recent call last): File "./main.py", line 73, in fn = bpf.load_func("udptcfilter", BPF.SCHED_CLS) File "/usr/lib/python3/dist-packages/bcc/init.py", line 412, in load_func (func_name, errstr)) Exception: Failed to load BPF program b'udptcfilter': Permission denied

my source code: #define L3_CSUM_OFF (ETH_HLEN + offsetof(struct iphdr, check)) #define IP_SRC_OFF (ETH_HLEN + offsetof(struct iphdr, saddr)) #define IP_DST_OFF (ETH_HLEN + offsetof(struct iphdr, daddr)) #define IP_TOTLEN_OFF (ETH_HLEN + offsetof(struct iphdr, tot_len))

#define L4_PORT_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct udphdr, dest )) #define L4_SRCPORT_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct udphdr, source )) #define L4_CSUM_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct udphdr, check)) #define L4_LEN_OFF (ETH_HLEN + sizeof(struct iphdr) + offsetof(struct udphdr, len ))

#define L4_RELAY_OFF ((ETH_HLEN + sizeof(struct iphdr) + sizeof(struct udphdr)))

struct relay_header { __u32 tag; __u32 srcIp; __u16 srcPort; __u16 dstPort; __u16 checksum; }attribute((packed));

#ifndef memcpy #define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) #endif

static inline int mutate_packet(struct __sk_buff *skb, __be32 target_addr, __be16 target_port, bool fwd_packet) { int ret; void *data = (void *)(long)skb->data; void *data_end = (void *)(long)skb->data_end; struct ethhdr *eth = data; struct iphdr *ip = (data + sizeof(struct ethhdr)); struct udphdr *udp = (data + sizeof(struct ethhdr) + sizeof(struct iphdr)); struct bpf_fib_lookup fib_params; struct relay_header rh; int rh_size = sizeof(rh);

// return early if not enough data
if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) + sizeof(struct udphdr) > data_end){
    return -1;
}

// only IP packets are allowed
if (eth->h_proto != bpf_htons(ETH_P_IP)){
    return -1;
}

// grab original destination addr
__u32 src_ip = ip->saddr;
__u32 dst_ip = ip->daddr;
__be16 tot_len  =  ip->tot_len;
__be16 new_tot = bpf_htons(bpf_ntohs(tot_len) + rh_size);
bpf_trace_printk("ip totlen:0x%x, new_tot:0x%x", tot_len, new_tot);
__be16 dst_port = udp->dest;
__be16 src_port = udp->source;
__be16 udp_len  = udp->len;
__be16 new_udp_len = bpf_htons(bpf_ntohs(udp_len) + rh_size);
bpf_trace_printk("udp_len:0x%x, new_len:0x%x", udp_len, new_udp_len);
if (fwd_packet) {
    __builtin_memset(&fib_params, 0, sizeof(fib_params));
    fib_params.family       = AF_INET;
    fib_params.tos          = ip->tos;
    fib_params.l4_protocol  = ip->protocol;
    fib_params.sport        = 0;
    fib_params.dport        = 0;
    fib_params.tot_len      = bpf_ntohs(ip->tot_len);
    fib_params.ipv4_src     = src_ip;
    fib_params.ipv4_dst     = target_addr;
    fib_params.ifindex      = skb->ingress_ifindex;

    ret = bpf_fib_lookup(skb, &fib_params, sizeof(fib_params), BPF_FIB_LOOKUP_DIRECT);

    if (ret != BPF_FIB_LKUP_RET_SUCCESS) {
        #ifdef DEBUG
        bpf_trace_printk("fib lookup result: %lu\n", ret);
        bpf_trace_printk("fib lookup src_ip= %lu dst_ip= %lu\n", src_ip, target_addr);
        #endif
        return -1;
    }
     bpf_trace_printk("before adjust tail, len: %d.", skb->data_end - skb->data);
    ret = bpf_skb_adjust_room(skb, rh_size, BPF_ADJ_ROOM_NET, BPF_F_ADJ_ROOM_ENCAP_L3_IPV4|BPF_F_ADJ_ROOM_ENCAP_L4_UDP);
    if (ret != 0) {
        bpf_trace_printk("adjust tail fail:%d.", ret);
        return -1;
    }
    
    bpf_trace_printk("after adjust tail, len: %d.", skb->data_end - skb->data);

    // set smac/dmac addr
    bpf_skb_store_bytes(skb, 0, &fib_params.dmac, sizeof(fib_params.dmac), 0);
    bpf_skb_store_bytes(skb, ETH_ALEN, &fib_params.smac, sizeof(fib_params.smac), 0);
}

#ifdef DEBUG
bpf_trace_printk("csum rewrite dst_ip= %lu target_addr= %lu\n", dst_ip, target_addr);
bpf_trace_printk("csum rewrite src_ip= %lu dst_ip= %lu\n", src_ip, dst_ip);
bpf_trace_printk("csum rewrite dst_port= %lu target_port= %lu\n", dst_port, target_port);
#endif

// recalc checksum
bpf_l4_csum_replace(skb, L4_CSUM_OFF, dst_ip, target_addr, sizeof(target_addr));
bpf_l4_csum_replace(skb, L4_CSUM_OFF, src_ip, dst_ip, sizeof(dst_ip));
bpf_l4_csum_replace(skb, L4_CSUM_OFF, dst_port, target_port, sizeof(target_port));
bpf_l4_csum_replace(skb, L4_CSUM_OFF, src_port, dst_port, sizeof(dst_port));
bpf_l4_csum_replace(skb, L4_CSUM_OFF, udp_len, new_udp_len, sizeof(new_udp_len));

bpf_l3_csum_replace(skb, L3_CSUM_OFF, dst_ip, target_addr, sizeof(target_addr));
bpf_l3_csum_replace(skb, L3_CSUM_OFF, src_ip, dst_ip, sizeof(dst_ip));
bpf_l3_csum_replace(skb, L3_CSUM_OFF, tot_len, new_tot, sizeof(tot_len));

// set src/dst addr
bpf_skb_store_bytes(skb, IP_TOTLEN_OFF, &new_tot, sizeof(tot_len), 0);
bpf_skb_store_bytes(skb, IP_SRC_OFF, &dst_ip, sizeof(dst_ip), 0);
bpf_skb_store_bytes(skb, IP_DST_OFF, &target_addr, sizeof(target_addr), 0);
bpf_skb_store_bytes(skb, L4_PORT_OFF, &target_port, sizeof(target_port), 0);
bpf_skb_store_bytes(skb, L4_SRCPORT_OFF, &dst_port, sizeof(dst_port), 0);
bpf_skb_store_bytes(skb, L4_LEN_OFF, &new_udp_len, sizeof(udp_len), 0);

bpf_skb_load_bytes(skb, IP_TOTLEN_OFF, &tot_len, sizeof(tot_len));
bpf_skb_load_bytes(skb, L4_LEN_OFF, &udp_len, sizeof(udp_len));

bpf_trace_printk("rewrite tot_len:0x%x, udp_len:0x%x", tot_len, udp_len);

bpf_skb_load_bytes(skb, L4_RELAY_OFF, &rh, sizeof(rh));
rh.tag = 0x31313131;
rh.srcIp = ip->saddr;
rh.srcPort = udp->source;
rh.dstPort = target_port;
rh.checksum = 0;

bpf_skb_load_bytes(skb, L4_RELAY_OFF, &rh, sizeof(rh));


if (fwd_packet){
    // clone packet, put it on interface found in fib
    bpf_trace_printk("fwd 1 packet, ifindex:%d\n", fib_params.ifindex);
    return bpf_clone_redirect(skb, fib_params.ifindex, 0);
}
return 0;

}

dark520xiang avatar Dec 17 '20 11:12 dark520xiang

I want to grow 14 bytes in the packet's buf , and rewrite my content .

dark520xiang avatar Dec 17 '20 11:12 dark520xiang