eBPF CO:RE:vmlinux.h 不完整?

eBPF CO:RE: vmlinux.h incomplete?

我正在尝试使用 libbpf 进入 eBPF CO:RE。我的程序使用跟踪点 SEC("tracepoint/syscalls/sys_enter_kill")),我想知道如何获取参数以及为什么它们不包含在 vmlinux.h 中。 此外,似乎缺少 define BPF_F_CURRENT_CPU 。或者可以组合 vmlinux.h 和 uapi/linux/bpf.h?

我的设置:

我知道已经有关于如何获取参数的问题 ()。但是,这并没有回答我的问题(为什么它不在vmlinux.h中?vmlinux.h还有什么意义?)而且我还有一个问题,内核显示的布局似乎不正确(见下文)。此外,似乎缺少定义 BPF_F_CURRENT_CPU。

我的代码:

common.h: 只有一个小结构来传输数据到用户空间

struct dataStruct {
    int pid;
};

main.bpf.c:

// Compiling with: clang -target bpf -S -D __BPF_TRACING__ -Wall -Werror -O2 -emit-llvm -c -g main.bpf.c
// and then: llc -march=bpf -filetype=obj -o main.bpf.o main.bpf.ll

#include "vmlinux.h"
#include "../90_lib/libbpf/build/root/usr/include/bpf/bpf_helpers.h"
#include "../90_lib/libbpf/build/root/usr/include/bpf/bpf_tracing.h"
#include "../90_lib/libbpf/build/root/usr/include/bpf/bpf_core_read.h"

#include "common.h"


struct {
    __uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
    __uint(key_size, sizeof(int));
    __uint(value_size, sizeof(int));
} pb SEC(".maps");
struct {
    __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY);
    __uint(max_entries, 1);
    __type(key, int);;
    __type(value, struct dataStruct);
} heap SEC(".maps");


// sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format
// name: sys_enter_kill
// ID: 184
// format:
//  field:unsigned short common_type;   offset:0;   size:2; signed:0;
//  field:unsigned char common_flags;   offset:2;   size:1; signed:0;
//  field:unsigned char common_preempt_count;   offset:3;   size:1;signed:0;
//  field:int common_pid;   offset:4;   size:4; signed:1;

//  field:int __syscall_nr; offset:8;   size:4; signed:1;
//  field:pid_t pid;    offset:16;  size:8; signed:0;
//  field:int sig;  offset:24;  size:8; signed:0;

// print fmt: "pid: 0x%08lx, sig: 0x%08lx", ((unsigned long)(REC->pid)), ((unsigned long)(REC->sig))


// >> How to obtain this structurecorrectly?
struct syscalls_enter_kill_args
{
    unsigned short common_type;
    unsigned char common_flags;
    unsigned char common_preempt_count;
    int common_pid;

    // int syscall_nr;      // From sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format
    // pid_t pid;
    // int sig;

    long syscall_nr;    // From https://hed.am/papers/2021-EBPF.pdf
    long pid;
    long sig;
};



enum {      // from #include "../90_lib/libbpf/include/uapi/linux/bpf.h"
    BPF_F_INDEX_MASK        = 0xffffffffULL,
    BPF_F_CURRENT_CPU       = BPF_F_INDEX_MASK,
/* BPF_FUNC_perf_event_output for sk_buff input context. */
    BPF_F_CTXLEN_MASK       = (0xfffffULL << 32),
};



SEC("tracepoint/syscalls/sys_enter_kill")
int kill_example(struct syscalls_enter_kill_args *ctx)
{
    if(ctx->sig != 9)
       return 0;

    // int s = BPF_CORE_READ(ctx, sig); // Does not work
    // if(s != 9)
    //  return 0;

    char fmt[] = "BPF handle\n";
    bpf_trace_printk(fmt, sizeof(fmt));


    struct dataStruct *e;
    int zero = 0;
    
    e = bpf_map_lookup_elem(&heap, &zero);
    if (!e) /* can't happen */
        return 0;

    e->pid = bpf_get_current_pid_tgid() >> 32;

    bpf_perf_event_output(ctx, &pb, BPF_F_CURRENT_CPU, e, sizeof(*e));

    return 0;
}

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

main.cc:

// Compile loader
// >> g++ -I../90_lib/libbpf/src/root/usr/include/ -L../90_lib/libbpf/src/ -o ebpf main.cc -lbpf -lelf -Wl,-R../90_lib/libbpf/src/


# include <stdio.h>
#include <iostream>
# include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/resource.h>

#include <poll.h>
#include <sys/select.h>

#include </usr/include/asm-generic/errno-base.h>


// Should be defined in up-to-date linux/bpf.h, but is not (and other linux/bpf.h conflicts with a lot of definitions)
/* type for BPF_ENABLE_STATS */
enum bpf_stats_type {
    /* enabled run_time_ns and run_cnt */
    BPF_STATS_RUN_TIME = 0,
};

#include "../90_lib/libbpf/build/root/usr/include/bpf/bpf.h"
#include "../90_lib/libbpf/build/root/usr/include/bpf/libbpf.h"

#include "common.h"


void bump_memlock_rlimit(void)
{
    struct rlimit rlim_new = {
        .rlim_cur   = RLIM_INFINITY,
        .rlim_max   = RLIM_INFINITY,
    };

    if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) {
        fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n");
        exit(1);
    }
}



using namespace std;

void handle_event(void *ctx, int cpu, void *data, unsigned int data_sz)
{
    cout << "perfBuffer - Event!; got " << data_sz << " Bytes? data." << endl;
    struct dataStruct* d = static_cast<struct dataStruct*>(data);
    cout << "    PID: " << d->pid << endl;
}



int main (int argc , char ** argv )
{
    int prog_fd ;
    struct bpf_object *obj;

    bump_memlock_rlimit();

    if(bpf_prog_load("main.bpf.o", BPF_PROG_TYPE_TRACEPOINT, &obj, &prog_fd) != 0)
    {
        printf (" eBPF program not loaded \n");
        return -1;
    }
    // Check that we got a file descriptor for the loaded object file.
    if(prog_fd < 1)
    {
        printf (" Error creating prog_fd \n");
        return -2;
    }
    // Attach the eBPF program by it 's function name
    struct bpf_program * prog = bpf_object__find_program_by_name(obj, "kill_example");
    bpf_program__attach(prog);

    int numMaps = 0;
    struct bpf_map * map;
    struct bpf_map* map_pb;

    struct bpf_map* maps[10];

    for (map = bpf_map__next(NULL, (obj));  \
         map != NULL;               \
         map = bpf_map__next(map, (obj)))
    {
        ++numMaps;
        cout << "Found map, name: '" << bpf_map__name(map) << "'" << endl;
        if(strcmp(bpf_map__name(map), "pb") == 0)
        {
            cout << "  Found map 'pb'; fileDescriptor: " << bpf_map__fd(map) << endl;
            map_pb = map;
        }
    }

    cout << "Found " << numMaps << " Maps." << endl;

    int map_pb_fd = bpf_map__fd(map_pb);
    cout << "Got Map File Descriptor: " << map_pb_fd << endl;

    uint32_t map_key_cnt = 0;
    uint64_t val = 0;
    uint64_t val_last = val;

    struct perf_buffer *pb = NULL;
    struct perf_buffer_opts pb_opts = {};
    pb_opts.sample_cb = handle_event;

    pb = perf_buffer__new(map_pb_fd, 8 /* 32KB per CPU */, &pb_opts);
    if (libbpf_get_error(pb)) {
        fprintf(stderr, "Failed to create perf buffer\n");
    }

    int res = 0;
    cout << "Entering main loop." << endl;
    while(1)
    {
        res = perf_buffer__poll(pb, -1);
        if(res == -EINTR)
        {
            cout << "-EINTR" << endl;
            return 0;
        }
    }
    return 0;
}

这适用于结构

struct syscalls_enter_kill_args
{
    unsigned short common_type;
    unsigned char common_flags;
    unsigned char common_preempt_count;
    int common_pid;

    long syscall_nr;    // From https://hed.am/papers/2021-EBPF.pdf
    long pid;
    long sig;
};

但不是当我将结构更改为

struct syscalls_enter_kill_args
{
    unsigned short common_type;
    unsigned char common_flags;
    unsigned char common_preempt_count;
    int common_pid;

    int syscall_nr;     // From sudo cat /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format
    pid_t pid;
    int sig;
};

这看起来很奇怪。有人知道哪里出了问题吗? 提前致谢! :)

唯一的原因是它不起作用,因为在这种情况下变量和大小的格式不匹配。 检查此文件的格式 sys_kill_enter /sys/kernel/debug/tracing/events/syscalls/sys_enter_kill/format

尽管 pid 字段是 pid_t 并且 sig 是 int.

但是如果你检查 pid 和 sig 的大小都是 8。

所以 longpid_t 没有的地方工作。