aquasecurity / libbpfgo

eBPF library for Go. Powered by libbpf.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

unknown func bpf_probe_read

SohnYu opened this issue · comments

commented

I want to read data from xdp_md and output it to user space, why bpf_probe_read can't be used. Or am I using it the wrong way?

//+build ignore
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

#define ETH_FRAME_LEN 1514
#define XDP_ACTION_MAX (XDP_REDIRECT + 1)

struct data_t {
__u32 len;
__u8 data[ETH_FRAME_LEN - sizeof(__u32)];
};

struct {
__uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
__uint(max_entries, XDP_ACTION_MAX);
__type(key, __u32);
__type(value, __u64);
} stats_map SEC(".maps");

struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 1024);
} rb SEC(".maps");

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

struct ethhdr *eth = data;
if ((void*)eth + sizeof(struct ethhdr) > data_end)
    return XDP_DROP;

struct iphdr *ip = data + sizeof(struct ethhdr);
if ((void*)ip + sizeof(struct iphdr) > data_end)
    return XDP_DROP;

if (ip->protocol == IPPROTO_TCP) {
    struct tcphdr *tcp = data + sizeof(struct ethhdr) + sizeof(struct iphdr);
    if ((void*)tcp + sizeof(struct tcphdr) > data_end)
        return XDP_DROP;
} else if (ip->protocol == IPPROTO_UDP) {
    struct udphdr *udp = data + sizeof(struct ethhdr) + sizeof(struct iphdr);
    if ((void*)udp + sizeof(struct udphdr) > data_end)
        return XDP_DROP;
} else {
    return XDP_PASS;
}

__u32 key = XDP_PASS;
__u64 *value;
value = bpf_map_lookup_elem(&stats_map, &key);
if (!value)
    return XDP_PASS;

__u32 len = (__u32)(data_end - data);
if (len > ETH_FRAME_LEN)
    len = ETH_FRAME_LEN;

struct data_t *pkt_data;
pkt_data = bpf_ringbuf_reserve(&rb, sizeof(pkt_data), 0);
if (!pkt_data)
    return XDP_DROP;

pkt_data->len = len - sizeof(struct ethhdr);

 __u32 offset = sizeof(struct ethhdr);
bpf_probe_read(pkt_data->data, pkt_data->len, data + offset);
bpf_ringbuf_submit(pkt_data, 0);

return XDP_PASS;

}

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

Ubuntu22.10 linux-header-5.19.0-31-generic

clang -g -O2 -Wall -fpie -target bpf -D__TARGET_ARCH_amd64 -I../../output -c main.bpf.c -o main.bpf.o
CC=clang
CGO_CFLAGS="-I/home/ysh/Nexus/libbpfgoStudy/output"
CGO_LDFLAGS="-lelf -lz /home/ysh/Nexus/libbpfgoStudy/output/libbpf.a"
GOOS=linux GOARCH=amd64
go build
-tags netgo -ldflags '-w -extldflags "-static"'
-o main-static ./main.go
sudo -S ./run.sh main-static
libbpf: prog 'xdp_prog': BPF program load failed: Invalid argument
libbpf: prog 'xdp_prog': -- BEGIN PROG LOAD LOG --
0: R1=ctx(off=0,imm=0) R10=fp0
; int xdp_prog(struct xdp_md *ctx) {
0: (b7) r0 = 1 ; R0_w=1
; void *data = (void *)(long)ctx->data;
1: (61) r9 = *(u32 *)(r1 +0) ; R1=ctx(off=0,imm=0) R9_w=pkt(off=0,r=0,imm=0)
; void *data_end = (void *)(long)ctx->data_end;
2: (61) r7 = (u32 )(r1 +4) ; R1=ctx(off=0,imm=0) R7_w=pkt_end(off=0,imm=0)
; if ((void
)eth + sizeof(struct ethhdr) > data_end)
3: (bf) r6 = r9 ; R6_w=pkt(off=0,r=0,imm=0) R9_w=pkt(off=0,r=0,imm=0)
4: (07) r6 += 14 ; R6_w=pkt(off=14,r=0,imm=0)
; if ((void
)eth + sizeof(struct ethhdr) > data_end)
5: (2d) if r6 > r7 goto pc+53 ; R6_w=pkt(off=14,r=14,imm=0) R7_w=pkt_end(off=0,imm=0)
6: (bf) r1 = r9 ; R1_w=pkt(off=0,r=14,imm=0) R9_w=pkt(off=0,r=14,imm=0)
7: (07) r1 += 34 ; R1_w=pkt(off=34,r=14,imm=0)
8: (b7) r0 = 1 ; R0_w=1
9: (2d) if r1 > r7 goto pc+49 ; R1_w=pkt(off=34,r=34,imm=0) R7_w=pkt_end(off=0,imm=0)
; if (ip->protocol == IPPROTO_TCP) {
10: (71) r1 = (u8 )(r6 +9) ; R1=scalar(umax=255,var_off=(0x0; 0xff)) R6=pkt(off=14,r=34,imm=0)
; if (ip->protocol == IPPROTO_TCP) {
11: (55) if r1 != 0x6 goto pc+5 ; R1=6
; if ((void
)tcp + sizeof(struct tcphdr) > data_end)
12: (bf) r1 = r9 ; R1_w=pkt(off=0,r=34,imm=0) R9=pkt(off=0,r=34,imm=0)
13: (07) r1 += 54 ; R1_w=pkt(off=54,r=34,imm=0)
14: (b7) r0 = 1 ; R0_w=1
15: (2d) if r1 > r7 goto pc+43 ; R1_w=pkt(off=54,r=54,imm=0) R7=pkt_end(off=0,imm=0)
16: (05) goto pc+7
; if ((void
)udp + sizeof(struct udphdr) > data_end)
24: (b7) r1 = 2 ; R1_w=2
; __u32 key = XDP_PASS;
25: (63) *(u32 *)(r10 -4) = r1 ; R1_w=2 R10=fp0 fp-8=mmmm????
26: (bf) r2 = r10 ; R2_w=fp0 R10=fp0
;
27: (07) r2 += -4 ; R2_w=fp-4
; value = bpf_map_lookup_elem(&stats_map, &key);
28: (18) r1 = 0xffff8a5703c6b200 ; R1_w=map_ptr(off=0,ks=4,vs=8,imm=0)
30: (85) call bpf_map_lookup_elem#1 ; R0=map_value_or_null(id=1,off=0,ks=4,vs=8,imm=0)
31: (bf) r1 = r0 ; R0=map_value_or_null(id=1,off=0,ks=4,vs=8,imm=0) R1_w=map_value_or_null(id=1,off=0,ks=4,vs=8,imm=0)
32: (b7) r0 = 2 ; R0_w=2
; if (!value)
33: (15) if r1 == 0x0 goto pc+25 ; R1_w=map_value(off=0,ks=4,vs=8,imm=0)
; pkt_data = bpf_ringbuf_reserve(&rb, sizeof(pkt_data), 0);
34: (18) r1 = 0xffff8a5703c6ac00 ; R1_w=map_ptr(off=0,ks=0,vs=0,imm=0)
36: (b7) r2 = 8 ; R2_w=8
37: (b7) r3 = 0 ; R3_w=0
38: (85) call bpf_ringbuf_reserve#131 ; R0_w=alloc_mem_or_null(id=3,ref_obj_id=3,off=0,imm=0) refs=3
39: (bf) r8 = r0 ; R0_w=alloc_mem_or_null(id=3,ref_obj_id=3,off=0,imm=0) R8_w=alloc_mem_or_null(id=3,ref_obj_id=3,off=0,imm=0) refs=3
40: (b7) r0 = 1 ; R0=1 refs=3
; if (!pkt_data)
41: (15) if r8 == 0x0 goto pc+17 ; R8=alloc_mem(ref_obj_id=3,off=0,imm=0) refs=3
; __u32 len = (__u32)(data_end - data);
42: (1f) r7 -= r9 ; R7_w=scalar() R9=pkt(off=0,r=54,imm=0) refs=3
43: (67) r7 <<= 32 ; R7_w=scalar(smax=9223372032559808512,umax=18446744069414584320,var_off=(0x0; 0xffffffff00000000),s32_min=0,s32_max=0,u32_max=0) refs=3
44: (77) r7 >>= 32 ; R7_w=scalar(umax=4294967295,var_off=(0x0; 0xffffffff)) refs=3
45: (b7) r1 = 1514 ; R1_w=1514 refs=3
; if (len > ETH_FRAME_LEN)
46: (2d) if r1 > r7 goto pc+1 ; R1_w=1514 R7_w=scalar(umin=1514,umax=4294967295,var_off=(0x0; 0xffffffff)) refs=3
47: (b7) r7 = 1514 ; R7_w=1514 refs=3
; pkt_data->len = len - sizeof(struct ethhdr);
48: (07) r7 += -14 ; R7_w=1500 refs=3
; pkt_data->len = len - sizeof(struct ethhdr);
49: (63) *(u32 *)(r8 +0) = r7 ; R7_w=1500 R8=alloc_mem(ref_obj_id=3,off=0,imm=0) refs=3
; bpf_probe_read(pkt_data->data, pkt_data->len, data + offset);
50: (bf) r1 = r8 ; R1_w=alloc_mem(ref_obj_id=3,off=0,imm=0) R8=alloc_mem(ref_obj_id=3,off=0,imm=0) refs=3
51: (07) r1 += 4 ; R1_w=alloc_mem(ref_obj_id=3,off=4,imm=0) refs=3
; bpf_probe_read(pkt_data->data, pkt_data->len, data + offset);
52: (bf) r2 = r7 ; R2_w=1500 R7_w=1500 refs=3
53: (bf) r3 = r6 ; R3_w=pkt(off=14,r=54,imm=0) R6=pkt(off=14,r=54,imm=0) refs=3
54: (85) call bpf_probe_read#4
unknown func bpf_probe_read#4
processed 46 insns (limit 1000000) max_states_per_insn 0 total_states 3 peak_states 3 mark_read 3
-- END PROG LOAD LOG --
libbpf: prog 'xdp_prog': failed to load: -22
libbpf: failed to load object 'main.bpf.o'
failed to load BPF object: invalid argument
make: *** [/home/ysh/Nexus/libbpfgoStudy/selftest/xdp/Makefile:85:run-static] 错误 4
[!] ERROR: test error

Take a look at:

https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#program-types

and check available bpf helpers inside the XDP program type:

image

And the base functions are:

image

I believe good examples for XDP programming can be found at: https://github.com/xdp-project/xdp-tutorial/blob/9807816aa19be3cba73f3d35061c7cacad161b86/packet01-parsing/xdp_prog_kern.c#L29

So I'm closing this, as it is unrelated to libbpfgo.