gobpf 使用示例:从 pt_regs 中获取内核函数的参数的值

前言

前面 pref event 示例中我们是通过 bpf_probe_read(&data.file_name, sizeof(data.file_name), PT_REGS_PARM2(ctx)) 获取的 do_sys_open 函数的 filename 参数的值, 本文简单讲述如何从 struct pt_regs *ctx 中获取内核函数的其他参数的值。

struct pt_regs *ctx 中获取内核函数的参数的值

本次示例将 tracing 内核函数 do_fchmodat ,这个函数的函数签名如下:

int do_fchmodat(int dfd, const char __user *filename, umode_t mode)

下面的代码片段将获取函数的 filename 和 mode 这两个参数的值,即这个函数的第二个参数和第三个参数的值:

struct data_t {
    __u32 pid;
    char file_name[256];
    __u32 mode;
};

SEC("kprobe/do_fchmodat")
int kprobe__do_fchmodat(struct pt_regs *ctx) {
        struct data_t data = {0};

        char *filename = (char *)PT_REGS_PARM2(ctx);
        unsigned int mode = PT_REGS_PARM3(ctx);

        bpf_probe_read(&data.file_name, sizeof(data.file_name), filename);

        data.mode = (__u32) mode;

        ...
}

上面的代码是通过 PT_REGS_PARM2PT_REGS_PARM3 这两个宏来分别获取第二个和第三参数的值的, 从名称就可以推断,第一个参数可以通过 PT_REGS_PARM1 来获取。

PT_REGS_PARM*bpf_helpers.h 定义的一些宏,用于快速从 pt_regs 中获取数据, 包括 PT_REGS_PARM1PT_REGS_PARM2PT_REGS_PARM3PT_REGS_PARM4PT_REGS_PARM5 可用于获取第一到第五个参数的值。

P.S. 本文的所有代码在 Github 上都有一份完整版: https://github.com/mozillazg/gobpf-examples/tree/master/3-chomd-pt_regs

上面的 ebpf 代码完整版运行后的效果如下:

$ make
$ make run

pid 52331 call fchmodat(fielname: a.txt, mode: 0775)

$ # make run 之后在另一个窗口执行
$ touch a.txt && strace chmod +x a.txt 2>&1 |grep chmod
execve("/usr/bin/chmod", ["chmod", "+x", "a.txt"], 0x7fffd601f570 /* 27 vars */) = 0
fchmodat(AT_FDCWD, "a.txt", 0775)       = 0

可以看到获取到的参数的值跟实际的值是一样的,符合预期。


Comments