cfc4n / ebpf-demo

ebpf demo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

您好,实在冒昧在这里问您问题,但是的确不太懂github的提问方式,有打扰您直接删掉就行,谢谢。

Killing11L opened this issue · comments

commented

我是想咨询您一个ebpf的问题,我当前需要做一个功能去获取一个文件的完整路径,就是通过循环一层一层通过struct dentry获取,拿到后拼接到一个512字节大小的空间内,但是因为每一级目录长度时变化的当我使用bpf_probe_read_kernel_str(filename + pos, len, name);这个接口时第二个参数并不能传入变量,下面时所有代码。

// ebpf.bpf.c
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#include "hiebpf.h"

#define FILE_TYPE_BITS 20
#define DCACHE_REGULAR_TYPE (0x00400000 >> FILE_TYPE_BITS) /* Regular file type (or fallthru to such) /
#define DCACHE_DIRECTORY_TYPE (0x00200000 >> FILE_TYPE_BITS) /
Normal directory */

struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, (1 << 24));
} bpf_ringbuf_map SEC(".maps");

static __always_inline
int handle_filename(char *filename, const size_t len, struct dentry *curr_dentry)
{
size_t pos = 0;
const u32 MAX_BACKTRACE_DEPTH = 20;
for (u32 cnt = MAX_BACKTRACE_DEPTH; cnt != 0; --cnt) {
if (curr_dentry == NULL) {
break;
}
int name_len = BPF_CORE_READ(curr_dentry, d_name.len);
// const u8 *name = BPF_CORE_READ(curr_dentry, d_name.name);
if (name_len <= 1) {
break;
}
char *temp = filename + pos;
int err = BPF_CORE_READ_STR_INTO(&temp, curr_dentry, d_name.name);

    // char msg[] = "MMMMMMM temp: %s";
    // bpf_trace_printk(msg, sizeof msg, temp);


    // name_len = bpf_probe_read_kernel_str(filename + pos, 10, name);
    // if (name_len <= 1) {
    //     break;
    // }
    pos += name_len;
    // filename[pos - 1] = '/';
    struct dentry *temp_dentry = BPF_CORE_READ(curr_dentry, d_parent);
    if (temp_dentry == curr_dentry || temp_dentry == NULL) {
        break;
    }
    curr_dentry = temp_dentry;
}
return pos;

}

SEC("kprobe/close_fd")
int BPF_KPROBE(__close_fd_entry,unsigned fd)
{
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
if (task == NULL) {
return 0;
}

if (fd >= BPF_CORE_READ(task, files, fdt, max_fds)) {
    return 0;
}

struct file **fd_array = BPF_CORE_READ(task, files, fdt, fd);
if (fd_array == NULL) {
    return 0;
}

struct file *filp = NULL;
int err = bpf_probe_read_kernel(&filp, sizeof(filp), &fd_array[fd]);
if (err || filp == NULL) {
    return 0;
}

struct inode *f_inode = BPF_CORE_READ(filp, f_inode);
if (f_inode == NULL) {
    return 0;
}

struct hlist_node *curr_hlist_node = BPF_CORE_READ(f_inode, i_dentry.first);
if (curr_hlist_node == NULL) {
    return 0;
}

const struct dentry *curr_dentry = NULL;
const u32 MAX_ALIAS_DENTRY = 100;
for (u32 cnt = MAX_ALIAS_DENTRY; cnt != 0; --cnt) {
    curr_dentry = container_of(curr_hlist_node, struct dentry, d_u);
    struct inode *curr_inode = BPF_CORE_READ(curr_dentry, d_inode);
    if (curr_inode == NULL) {
        return 0;
    }
    if (curr_inode == f_inode) {
        break;
    }
    curr_hlist_node = BPF_CORE_READ(curr_hlist_node, next);
    if (curr_hlist_node == NULL) {
        break;
    }
}

unsigned int flags = BPF_CORE_READ(curr_dentry, d_flags);
flags = (flags & 0xFFFFFF) >> FILE_TYPE_BITS;
if (flags != DCACHE_DIRECTORY_TYPE && flags != DCACHE_REGULAR_TYPE) {
    return 0;
}

struct hi_filename *path = bpf_ringbuf_reserve(&bpf_ringbuf_map, sizeof(struct hi_filename), 0);
if (path == NULL) {
    return -1;
}
__builtin_memset(path, 0, sizeof(struct hi_filename));

handle_filename(path->path, 512, curr_dentry);

char msg[] = "MMMMMMM path: %s";
bpf_trace_printk(msg, sizeof msg, path->path);
bpf_ringbuf_submit(path, 2);
return 0;

}

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

// ebpf.c
#include <stdio.h>
#include <bpf/libbpf.h>
#include <bpf/bpf.h>
#include "hiebpf.skel.h"
#include "hiebpf.h"
#include <sys/time.h>
#include <sys/resource.h>

void HandleEvent(void *ctx, void *data, size_t dataSize)
{
struct hi_filename *name = (struct hi_filename *)data;

// printf("11111!!! name: %s\n", name->path);

}

int main()
{
libbpf_set_strict_mode(LIBBPF_STRICT_ALL);

struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
setrlimit(RLIMIT_MEMLOCK, &r);


struct hiebpf_bpf *obj = hiebpf_bpf__open();
int err = hiebpf_bpf__load(obj);
if (err) {
    printf("加载失败!!!\n");
    return err;
}

err = hiebpf_bpf__attach(obj);
if (err) {
    printf("干活失败!!!\n");
    return -1;
}
printf("干活!!!\n");

struct ring_buffer* rb_ = ring_buffer__new(bpf_map__fd(obj->maps.bpf_ringbuf_map), HandleEvent, NULL, NULL);

while (1) {
	err = ring_buffer__poll(rb_, 100 /* timeout, ms */);
	/* Ctrl-C will cause -EINTR */
	if (err == -EINTR) {
		err = 0;
		break;
	}
	if (err < 0) {
		printf("Error polling perf buffer: %d\n", err);
		break;
	}
}

return 0;

}

// ebof.h
struct hi_filename {
char path[512];
};

我最终的目的是想512字节前的目录每一级都保存完整,最后超过512的截断。我已经尝试基本上所有方式吧,都没有解决。
感谢您的阅读,有打扰非常抱歉,非常感谢。

commented

理解你的行为。这几天我生病了,等康复后再详细回答你。你可以先看看ehids/ehids-agent仓库的kern/bpf_call_kern.c 里的实现。

commented

好的,非常感谢您~~

commented

对了我再说一下就是失败的libbpf库的报错一般是说复制字符串超过了越界或者什么的,但是我之前在bpf_probe_read_kernel_str之前做了各种限制判断,不过都是失败的。

commented

搜一些 ebpf验证器的文章看看吧。

commented

好的,谢谢~