Search code examples
c++ebpf

ebpf beginner question: bpf_trace_printk causing error?


I am new to ebpf and trying to use ebpf to inspect tcp packets.

I hooked kprobe on tcp_v4_rcv() and my programs are below (just modified a helloworld program):

//hello_kern.c

#include <linux/tcp.h>
#include <uapi/linux/bpf.h>
#include <uapi/linux/tcp.h>
#include "bpf_helpers.h"

SEC("kprobe/tcp_v4_rcv")
int bpf_prog(void *ctx, struct sk_buff* skb)
{
    struct tcphdr* th;
    int dest;
    char msg[] = "hello world! My dest is %d\n";

    th = tcp_hdr(skb);
    dest = th->dest;
    bpf_trace_printk(msg, sizeof(msg), dest); //comment this line can make program run
    return 0;
}

char _license[] SEC("license") = "GPL";
//hello_user.c

#include "bpf_load.h"

int main(void)
{
    if (load_bpf_file("hello_kern.o"))
        return -1;
    read_trace_pipe();

    return 0;
}

Compiling was just fine. But when I run this program the following error happened:

bpf_load_program() err=13
0: (b7) r1 = 680997
1: (63) *(u32 *)(r10 -8) = r1
2: (18) r1 = 0x2073692074736564
4: (7b) *(u64 *)(r10 -16) = r1
5: (18) r1 = 0x20794d2021646c72
7: (7b) *(u64 *)(r10 -24) = r1
8: (18) r1 = 0x6f77206f6c6c6568
10: (7b) *(u64 *)(r10 -32) = r1
11: (69) r1 = *(u16 *)(r2 +178)
R2 !read_ok
processed 9 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

I tried comment the line of "bpf_trace_printk" and program just run successfully (without anything printed out). Did I use bpf_trace_printk wrong?

btw is there any well-organized ebpf tutorial or documents I can refer to? I can only find some tutorial blogs. If anyone knows please tell me. thx :)


Solution

  • Anyway I tried many times and finally code below works.

    Key points: 1. use bpf_probe_read to read address in kernel space; 2. do not use tcp_hdr().

    #include <linux/tcp.h>
    #include <linux/skbuff.h>
    #include <uapi/linux/bpf.h>
    #include <uapi/linux/tcp.h>
    #include "bpf_helpers.h"
    
    SEC("kprobe/tcp_v4_rcv")
    int bpf_prog(struct pt_regs *ctx)
    {
        struct sk_buff *skb= (struct sk_buff *)PT_REGS_PARM1(ctx);
    
        struct tcphdr *th;
        unsigned short dest;
        char msg[] = "hello world! My dest is %u\n";
    
        bpf_probe_read(&th, sizeof(struct tcphdr *), &(skb->data));
        // bpf_probe_read(th, sizeof(struct tcphdr *), (skb->data)); Wrong! idk why.
        bpf_probe_read(&dest, sizeof(unsigned short), &(th->dest));
        bpf_trace_printk(msg, sizeof(msg), ntohs(dest));
        return 0;
    }
    
    char _license[] SEC("license") = "GPL";