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

NobinPegasus

Member
Joined
Feb 4, 2022
Messages
50
Reaction score
0
Credits
447
I've completed the assignment as mentioned in the solutions.
Here's the repo I'm trying to test on my local machine:

Here's my C code:
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 to compile and run this program:
Code:
cd packet01-parsing
make
sudo ip link set dev test xdpgeneric obj xdp_prog_kern.o sec xdp

Code:
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?
 

Members online


Top