Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

invalid access to map value, value_size=128 off=0 size=0; libbpf: prog 'xdp_parser_func': failed to load: -13 #413

Open
NobinPegasus opened this issue Mar 28, 2024 · 2 comments

Comments

@NobinPegasus
Copy link

I've completed the assignment as mentioned in the solutions.
Here's my C code:

/* SPDX-License-Identifier: GPL-2.0 */
#include <stddef.h>
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
/* Defines xdp_stats_map from packet04 */
#include "../common/xdp_stats_kern_user.h"
#include "../common/xdp_stats_kern.h"

/* Header cursor to keep track of current parsing position */

/* Packet parsing helpers.
 *
 * Each helper parses a packet header, including doing bounds checking, and
 * returns the type of its contents if successful, and -1 otherwise.
 *
 * For Ethernet and IP headers, the content type is the type of the payload
 * (h_proto for Ethernet, nexthdr for IPv6), for ICMP it is the ICMP type field.
 * All return values are in host byte order.
 */

#include <linux/ip.h>
#include <linux/icmp.h>
#include <linux/udp.h>
#include <linux/tcp.h>

/* Header cursor to keep track of current parsing position */
struct hdr_cursor {
	void *pos;
};

/*
 *	struct vlan_hdr - vlan header
 *	@h_vlan_TCI: priority and VLAN ID
 *	@h_vlan_encapsulated_proto: packet type ID or len
 */
struct vlan_hdr {
	__be16	h_vlan_TCI;
	__be16	h_vlan_encapsulated_proto;
};

/*
 * Struct icmphdr_common represents the common part of the icmphdr and icmp6hdr
 * structures.
 */
struct icmphdr_common {
	__u8		type;
	__u8		code;
	__sum16	cksum;
};

/* Allow users of header file to redefine VLAN max depth */
#ifndef VLAN_MAX_DEPTH
#define VLAN_MAX_DEPTH 2
#endif

#define VLAN_VID_MASK		0x0fff /* VLAN Identifier */
/* Struct for collecting VLANs after parsing via parse_ethhdr_vlan */
struct collect_vlans {
	__u16 id[VLAN_MAX_DEPTH];
};

static __always_inline int proto_is_vlan(__u16 h_proto)
{
	return !!(h_proto == bpf_htons(ETH_P_8021Q) ||
		  h_proto == bpf_htons(ETH_P_8021AD));
}

/* Notice, parse_ethhdr() will skip VLAN tags, by advancing nh->pos and returns
 * next header EtherType, BUT the ethhdr pointer supplied still points to the
 * Ethernet header. Thus, caller can look at eth->h_proto to see if this was a
 * VLAN tagged packet.
 */
static __always_inline int parse_ethhdr_vlan(struct hdr_cursor *nh,
					     void *data_end,
					     struct ethhdr **ethhdr,
					     struct collect_vlans *vlans)
{
	struct ethhdr *eth = nh->pos;
	int hdrsize = sizeof(*eth);
	struct vlan_hdr *vlh;
	__u16 h_proto;
	int i;

	/* Byte-count bounds check; check if current pointer + size of header
	 * is after data_end.
	 */
	if (nh->pos + hdrsize > data_end)
		return -1;

	nh->pos += hdrsize;
	*ethhdr = eth;
	vlh = nh->pos;
	h_proto = eth->h_proto;

	/* Use loop unrolling to avoid the verifier restriction on loops;
	 * support up to VLAN_MAX_DEPTH layers of VLAN encapsulation.
	 */
	#pragma unroll
	for (i = 0; i < VLAN_MAX_DEPTH; i++) {
		if (!proto_is_vlan(h_proto))
			break;

		if (vlh + 1 > data_end)
			break;

		h_proto = vlh->h_vlan_encapsulated_proto;
		if (vlans) /* collect VLAN ids */
			vlans->id[i] =
				(bpf_ntohs(vlh->h_vlan_TCI) & VLAN_VID_MASK);

		vlh++;
	}

	nh->pos = vlh;
	return h_proto; /* network-byte-order */
}

static __always_inline int parse_ethhdr(struct hdr_cursor *nh,
					void *data_end,
					struct ethhdr **ethhdr)
{
	/* Expect compiler removes the code that collects VLAN ids */
	return parse_ethhdr_vlan(nh, data_end, ethhdr, NULL);
}

// static __always_inline int parse_ip6hdr(struct hdr_cursor *nh,
// 					void *data_end,
// 					struct ipv6hdr **ip6hdr)
// {
// 	struct ipv6hdr *ip6h = nh->pos;

// 	/* Pointer-arithmetic bounds check; pointer +1 points to after end of
// 	 * thing being pointed to. We will be using this style in the remainder
// 	 * of the tutorial.
// 	 */
// 	if (ip6h + 1 > data_end)
// 		return -1;

// 	nh->pos = ip6h + 1;
// 	*ip6hdr = ip6h;

// 	return ip6h->nexthdr;
// }

static __always_inline int parse_iphdr(struct hdr_cursor *nh,
				       void *data_end,
				       struct iphdr **iphdr)
{
	struct iphdr *iph = nh->pos;
	int hdrsize;

	if (iph + 1 > data_end)
		return -1;

	hdrsize = iph->ihl * 4;
	/* Sanity check packet field is valid */
	if(hdrsize < sizeof(*iph))
		return -1;

	/* Variable-length IPv4 header, need to use byte-based arithmetic */
	if (nh->pos + hdrsize > data_end)
		return -1;

	nh->pos += hdrsize;
	*iphdr = iph;

	return iph->protocol;
}

// static __always_inline int parse_icmp6hdr(struct hdr_cursor *nh,
// 					  void *data_end,
// 					  struct icmp6hdr **icmp6hdr)
// {
// 	struct icmp6hdr *icmp6h = nh->pos;

// 	if (icmp6h + 1 > data_end)
// 		return -1;

// 	nh->pos   = icmp6h + 1;
// 	*icmp6hdr = icmp6h;

// 	return icmp6h->icmp6_type;
// }

static __always_inline int parse_icmphdr(struct hdr_cursor *nh,
					 void *data_end,
					 struct icmphdr **icmphdr)
{
	struct icmphdr *icmph = nh->pos;

	if (icmph + 1 > data_end)
		return -1;

	nh->pos  = icmph + 1;
	*icmphdr = icmph;

	return icmph->type;
}

// static __always_inline int parse_icmphdr_common(struct hdr_cursor *nh,
// 						void *data_end,
// 						struct icmphdr_common **icmphdr)
// {
// 	struct icmphdr_common *h = nh->pos;

// 	if (h + 1 > data_end)
// 		return -1;

// 	nh->pos  = h + 1;
// 	*icmphdr = h;

// 	return h->type;
// }

/*
 * parse_udphdr: parse the udp header and return the length of the udp payload
 */
// static __always_inline int parse_udphdr(struct hdr_cursor *nh,
// 					void *data_end,
// 					struct udphdr **udphdr)
// {
// 	int len;
// 	struct udphdr *h = nh->pos;

// 	if (h + 1 > data_end)
// 		return -1;

// 	nh->pos  = h + 1;
// 	*udphdr = h;

// 	len = bpf_ntohs(h->len) - sizeof(struct udphdr);
// 	if (len < 0)
// 		return -1;

// 	return len;
// }

/*
 * parse_tcphdr: parse and return the length of the tcp header
 */
// static __always_inline int parse_tcphdr(struct hdr_cursor *nh,
// 					void *data_end,
// 					struct tcphdr **tcphdr)
// {
// 	int len;
// 	struct tcphdr *h = nh->pos;

// 	if (h + 1 > data_end)
// 		return -1;

// 	len = h->doff * 4;
// 	/* Sanity check packet field is valid */
// 	if(len < sizeof(*h))
// 		return -1;

// 	/* Variable-length TCP header, need to use byte-based arithmetic */
// 	if (nh->pos + len > data_end)
// 		return -1;

// 	nh->pos += len;
// 	*tcphdr = h;

// 	return len;
// }

// static __always_inline __u16 my_ntohs(__u16 netshort) {
//     return ((netshort & 0xFF00) >> 8) | ((netshort & 0x00FF) << 8);
// }


SEC("xdp")
int xdp_parser_func(struct xdp_md *ctx)
{
    void *data_end = (void *)(long)ctx->data_end;
    void *data = (void *)(long)ctx->data;
    struct ethhdr *eth;

    /* Default action XDP_PASS, imply everything we couldn't parse, or that
     * we don't want to deal with, we just pass up the stack and let the
     * kernel deal with it.
     */
    __u32 action = XDP_PASS; /* Default action */

    /* These keep track of the next header type and iterator pointer */
    struct hdr_cursor nh;
    int nh_type;

    /* Start next header cursor position at data start */
    nh.pos = data;

    /* Packet parsing in steps: Get each header one at a time, aborting if
     * parsing fails. Each helper function does sanity checking (is the
     * header type in the packet correct?), and bounds checking.
     */
    nh_type = parse_ethhdr(&nh, data_end, &eth);
    if (nh_type == bpf_htons(ETH_P_8021Q)) {
        struct collect_vlans vlans;
        int vlan_proto = parse_ethhdr_vlan(&nh, data_end, &eth, &vlans);
        if (vlan_proto < 0)
            goto out;

        // Print VLAN information
        for (int i = 0; i < VLAN_MAX_DEPTH; i++) {
            if (vlans.id[i] == 0)
                break;
            bpf_trace_printk("VLAN ID[%d] = %u\n", i, vlans.id[i]);
        }
    }

    // Proceed to IPv4 or IPv6 parsing
//     if (nh_type == bpf_htons(ETH_P_IPV6)) {
//         struct ipv6hdr *ip6hdr;
//         int ip6_next_header = parse_ip6hdr(&nh, data_end, &ip6hdr);
//         if (ip6_next_header == IPPROTO_ICMPV6) {
//             struct icmp6hdr *icmp6hdr;
//             int icmp6_type = parse_icmp6hdr(&nh, data_end, &icmp6hdr);
//             if (icmp6_type < 0)
//                 goto out;

//             // Print IPv6 header information
// bpf_trace_printk("IPv6 Header: Source Address = %x:%x:%x:%x:%x:%x:%x:%x, Destination Address = %x:%x:%x:%x:%x:%x:%x:%x\n",
//                  my_ntohs(ip6hdr->saddr.s6_addr16[0]), my_ntohs(ip6hdr->saddr.s6_addr16[1]),
//                  my_ntohs(ip6hdr->saddr.s6_addr16[2]), my_ntohs(ip6hdr->saddr.s6_addr16[3]),
//                  my_ntohs(ip6hdr->saddr.s6_addr16[4]), my_ntohs(ip6hdr->saddr.s6_addr16[5]),
//                  my_ntohs(ip6hdr->saddr.s6_addr16[6]), my_ntohs(ip6hdr->saddr.s6_addr16[7]),
//                  my_ntohs(ip6hdr->daddr.s6_addr16[0]), my_ntohs(ip6hdr->daddr.s6_addr16[1]),
//                  my_ntohs(ip6hdr->daddr.s6_addr16[2]), my_ntohs(ip6hdr->daddr.s6_addr16[3]),
//                  my_ntohs(ip6hdr->daddr.s6_addr16[4]), my_ntohs(ip6hdr->daddr.s6_addr16[5]),
//                  my_ntohs(ip6hdr->daddr.s6_addr16[6]), my_ntohs(ip6hdr->daddr.s6_addr16[7]));

//             bpf_trace_printk("Next Header = %d\n", ip6hdr->nexthdr);

//             // Print ICMPv6 header information
//             bpf_trace_printk("ICMPv6 Header: Type = %d, Code = %d\n",
//                              icmp6hdr->icmp6_type, icmp6hdr->icmp6_code);
//         }
//     }
	 if (nh_type == bpf_htons(ETH_P_IP)) {
        struct iphdr *iphdr;
        int ip_next_header = parse_iphdr(&nh, data_end, &iphdr);
        if (ip_next_header == IPPROTO_ICMP) {
            struct icmphdr *icmphdr;
            int icmp_type = parse_icmphdr(&nh, data_end, &icmphdr);
            if (icmp_type < 0)
                goto out;

            // Print IPv4 header information
			bpf_trace_printk("IPv4 Header: Source Address = %x, Destination Address = %x\n",
                 bpf_ntohl(iphdr->saddr), bpf_ntohl(iphdr->daddr));

            bpf_trace_printk("Protocol = %d\n", iphdr->protocol);

            // Print ICMP header information
            bpf_trace_printk("ICMP Header: Type = %d, Code = %d\n",
                             icmphdr->type, icmphdr->code);
        }
    }

    // Add more parsing or processing for IPv6, ICMPv6, VLAN, IPv4, and ICMP headers here if needed

    // Set action based on parsed headers
    // For example, drop packets with certain conditions
    
    // action = XDP_DROP;

out:
    return xdp_stats_record_action(ctx, action); /* read via xdp_stats */
}

char _license[] SEC("license") = "GPL";

Command used:

cd packet01-parsing
make
sudo ip link set dev test xdpgeneric obj xdp_prog_kern.o sec xdp
pegasus@pegasus:~/Documents/xdp-tutorial/packet01-parsing$ sudo ip link set dev test xdpgeneric obj xdp_prog_kern.o sec xdp
[sudo] password for pegasus: 
libbpf: prog 'xdp_parser_func': BPF program load failed: Permission denied
libbpf: prog 'xdp_parser_func': -- BEGIN PROG LOAD LOG --
0: R1=ctx(off=0,imm=0) R10=fp0
; int xdp_parser_func(struct xdp_md *ctx)
0: (bf) r6 = r1                       ; R1=ctx(off=0,imm=0) R6_w=ctx(off=0,imm=0)
; void *data_end = (void *)(long)ctx->data_end;
1: (61) r1 = *(u32 *)(r6 +4)          ; R1_w=pkt_end(off=0,imm=0) R6_w=ctx(off=0,imm=0)
; void *data = (void *)(long)ctx->data;
2: (61) r3 = *(u32 *)(r6 +0)          ; R3_w=pkt(off=0,r=0,imm=0) R6_w=ctx(off=0,imm=0)
; if (nh->pos + hdrsize > data_end)
3: (bf) r8 = r3                       ; R3_w=pkt(off=0,r=0,imm=0) R8_w=pkt(off=0,r=0,imm=0)
4: (07) r8 += 14                      ; R8_w=pkt(off=14,r=0,imm=0)
; if (nh->pos + hdrsize > data_end)
5: (2d) if r8 > r1 goto pc+73         ; R1_w=pkt_end(off=0,imm=0) R8_w=pkt(off=14,r=14,imm=0)
; 
6: (71) r4 = *(u8 *)(r3 +12)          ; R3_w=pkt(off=0,r=14,imm=0) R4_w=scalar(umax=255,var_off=(0x0; 0xff))
7: (71) r2 = *(u8 *)(r3 +13)          ; R2_w=scalar(umax=255,var_off=(0x0; 0xff)) R3_w=pkt(off=0,r=14,imm=0)
8: (67) r2 <<= 8                      ; R2_w=scalar(umax=65280,var_off=(0x0; 0xff00))
9: (4f) r2 |= r4                      ; R2_w=scalar() R4_w=scalar(umax=255,var_off=(0x0; 0xff))
; if (!proto_is_vlan(h_proto))
10: (15) if r2 == 0xa888 goto pc+1    ; R2_w=scalar()
11: (55) if r2 != 0x81 goto pc+19     ; R2=129
; if (vlh + 1 > data_end)
12: (bf) r4 = r3                      ; R3=pkt(off=0,r=14,imm=0) R4_w=pkt(off=0,r=14,imm=0)
13: (07) r4 += 18                     ; R4_w=pkt(off=18,r=14,imm=0)
; if (vlh + 1 > data_end)
14: (2d) if r4 > r1 goto pc+16        ; R1=pkt_end(off=0,imm=0) R4_w=pkt(off=18,r=18,imm=0)
; 
15: (71) r5 = *(u8 *)(r3 +16)         ; R3=pkt(off=0,r=18,imm=0) R5_w=scalar(umax=255,var_off=(0x0; 0xff))
16: (71) r2 = *(u8 *)(r3 +17)         ; R2_w=scalar(umax=255,var_off=(0x0; 0xff)) R3=pkt(off=0,r=18,imm=0)
17: (67) r2 <<= 8                     ; R2_w=scalar(umax=65280,var_off=(0x0; 0xff00))
18: (4f) r2 |= r5                     ; R2=scalar() R5=scalar(umax=255,var_off=(0x0; 0xff))
; if (!proto_is_vlan(h_proto))
19: (15) if r2 == 0xa888 goto pc+2    ; R2=scalar()
20: (bf) r8 = r4                      ; R4=pkt(off=18,r=18,imm=0) R8_w=pkt(off=18,r=18,imm=0)
21: (55) if r2 != 0x81 goto pc+9      ; R2=129
; if (vlh + 1 > data_end)
22: (bf) r5 = r3                      ; R3=pkt(off=0,r=18,imm=0) R5_w=pkt(off=0,r=18,imm=0)
23: (07) r5 += 22                     ; R5_w=pkt(off=22,r=18,imm=0)
24: (bf) r8 = r4                      ; R4=pkt(off=18,r=18,imm=0) R8_w=pkt(off=18,r=18,imm=0)
; if (vlh + 1 > data_end)
25: (2d) if r5 > r1 goto pc+5         ; R1=pkt_end(off=0,imm=0) R5_w=pkt(off=22,r=22,imm=0)
; 
26: (71) r4 = *(u8 *)(r3 +20)         ; R3=pkt(off=0,r=22,imm=0) R4_w=scalar(umax=255,var_off=(0x0; 0xff))
27: (71) r2 = *(u8 *)(r3 +21)         ; R2_w=scalar(umax=255,var_off=(0x0; 0xff)) R3=pkt(off=0,r=22,imm=0)
28: (67) r2 <<= 8                     ; R2_w=scalar(umax=65280,var_off=(0x0; 0xff00))
29: (4f) r2 |= r4                     ; R2_w=scalar() R4_w=scalar(umax=255,var_off=(0x0; 0xff))
30: (bf) r8 = r5                      ; R5=pkt(off=22,r=22,imm=0) R8=pkt(off=22,r=22,imm=0)
; if (nh_type == bpf_htons(ETH_P_8021Q)) {
31: (15) if r2 == 0x8 goto pc+70      ; R2=scalar()
32: (55) if r2 != 0x81 goto pc+46     ; R2=129
; if (nh->pos + hdrsize > data_end)
33: (bf) r2 = r8                      ; R2_w=pkt(off=22,r=22,imm=0) R8=pkt(off=22,r=22,imm=0)
34: (07) r2 += 14                     ; R2_w=pkt(off=36,r=22,imm=0)
; if (nh->pos + hdrsize > data_end)
35: (2d) if r2 > r1 goto pc+43        ; R1=pkt_end(off=0,imm=0) R2_w=pkt(off=36,r=36,imm=0)
; h_proto = eth->h_proto;
36: (71) r3 = *(u8 *)(r8 +12)         ; R3_w=scalar(umax=255,var_off=(0x0; 0xff)) R8=pkt(off=22,r=36,imm=0)
37: (71) r2 = *(u8 *)(r8 +13)         ; R2_w=scalar(umax=255,var_off=(0x0; 0xff)) R8=pkt(off=22,r=36,imm=0)
38: (67) r2 <<= 8                     ; R2_w=scalar(umax=65280,var_off=(0x0; 0xff00))
39: (4f) r2 |= r3                     ; R2=scalar() R3=scalar(umax=255,var_off=(0x0; 0xff))
; if (!proto_is_vlan(h_proto))
40: (15) if r2 == 0xa888 goto pc+1    ; R2=scalar()
41: (55) if r2 != 0x81 goto pc+92     ; R2=129
; if (vlh + 1 > data_end)
42: (bf) r2 = r8                      ; R2_w=pkt(off=22,r=36,imm=0) R8=pkt(off=22,r=36,imm=0)
43: (07) r2 += 18                     ; R2_w=pkt(off=40,r=36,imm=0)
; if (vlh + 1 > data_end)
44: (2d) if r2 > r1 goto pc+89        ; R1=pkt_end(off=0,imm=0) R2_w=pkt(off=40,r=40,imm=0)
; h_proto = vlh->h_vlan_encapsulated_proto;
45: (69) r5 = *(u16 *)(r8 +16)        ; R5_w=scalar(umax=65535,var_off=(0x0; 0xffff)) R8=pkt(off=22,r=40,imm=0)
46: (b7) r4 = 1                       ; R4_w=1
47: (b7) r3 = 1                       ; R3=1
; return !!(h_proto == bpf_htons(ETH_P_8021Q) ||
48: (55) if r5 != 0x81 goto pc+1      ; R5=129
49: (b7) r3 = 0                       ; R3_w=0
; return !!(h_proto == bpf_htons(ETH_P_8021Q) ||
50: (55) if r5 != 0xa888 goto pc+1    ; R5=129
; if (!proto_is_vlan(h_proto))
52: (5f) r4 &= r3                     ; R3_w=0 R4_w=0
; (bpf_ntohs(vlh->h_vlan_TCI) & VLAN_VID_MASK);
53: (69) r3 = *(u16 *)(r8 +14)        ; R3_w=scalar(umax=65535,var_off=(0x0; 0xffff)) R8=pkt(off=22,r=40,imm=0)
; (bpf_ntohs(vlh->h_vlan_TCI) & VLAN_VID_MASK);
54: (57) r3 &= -241                   ; R3_w=scalar(umax=65295,var_off=(0x0; 0xff0f))
; if (!proto_is_vlan(h_proto))
55: (57) r4 &= 1                      ; R4_w=0
56: (55) if r4 != 0x0 goto pc+5       ; R4_w=0
57: (07) r8 += 22                     ; R8=pkt(off=44,r=40,imm=0)
58: (2d) if r8 > r1 goto pc+3         ; R1=pkt_end(off=0,imm=0) R8=pkt(off=44,r=44,imm=0)
; (bpf_ntohs(vlh->h_vlan_TCI) & VLAN_VID_MASK);
59: (69) r7 = *(u16 *)(r2 +0)         ; R2=pkt(off=40,r=44,imm=0) R7_w=scalar(umax=65535,var_off=(0x0; 0xffff))
; (bpf_ntohs(vlh->h_vlan_TCI) & VLAN_VID_MASK);
60: (57) r7 &= 65295                  ; R7_w=scalar(umax=65295,var_off=(0x0; 0xff0f))
61: (dc) r7 = be16 r7                 ; R7_w=scalar()
; if (vlans.id[i] == 0)
62: (bf) r1 = r3                      ; R1_w=scalar(id=1,umax=65295,var_off=(0x0; 0xff0f)) R3=scalar(id=1,umax=65295,var_off=(0x0; 0xff0f))
63: (57) r1 &= 65535                  ; R1_w=scalar(umax=65295,var_off=(0x0; 0xff0f))
; if (vlans.id[i] == 0)
64: (15) if r1 == 0x0 goto pc+14      ; R1_w=scalar(umax=65295,var_off=(0x0; 0xff0f))
; 
65: (dc) r3 = be16 r3                 ; R3_w=scalar()
; bpf_trace_printk("VLAN ID[%d] = %u\n", i, vlans.id[i]);
66: (18) r1 = 0xffff948a54165510      ; R1_w=map_value(off=0,ks=4,vs=128,imm=0)
68: (b7) r2 = 0                       ; R2_w=0
69: (85) call bpf_trace_printk#6
invalid access to map value, value_size=128 off=0 size=0
R1 min value is outside of the allowed memory range
processed 68 insns (limit 1000000) max_states_per_insn 0 total_states 6 peak_states 6 mark_read 2
-- END PROG LOAD LOG --
libbpf: prog 'xdp_parser_func': failed to load: -13
libbpf: failed to load object 'xdp_prog_kern.o'

Why am I facing this error? How can I fix it?

@tohojo
Copy link
Member

tohojo commented Apr 4, 2024 via email

@NobinPegasus
Copy link
Author

@tohojo I've replaced all bpf_trace_printk with bpf_printk. Still seeing the same issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants