BPF_KPROBE 宏提供了系统调用参数的意外值
BPF_KPROBE macro provides unexpected value of the syscall argument
在使用 libbpf-bootstrap 时,我得到了 kprobe 系统调用的意外(和奇怪)函数参数。例如,对于带有 int close(inf fd)
签名的 close
系统调用上的 kprobe,我得到了巨大的 fd
值,如 fd=15761240
,而预期的是小整数,如 fd=4
。转载于 Debian 11 x64 (kernel 5.10.0-7-amd64)
和 Ubuntu 21.10 x64 (kernel ~5.13)
。
调试代码:
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
char LICENSE[] SEC("license") = "Dual BSD/GPL";
// accept4 syscall
// int accept4(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen);
SEC("kretprobe/__x64_sys_accept4")
int BPF_KRETPROBE(accept, int ret) {
u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32;
// filter specific pid for simplicity
if (pid != 31114 || ret < 0) {
return 0;
}
// debug returned file descriptor
bpf_printk("opened pid=%d fd=%d", pid, ret);
return 0;
}
// close syscall
// int close(int fd);
SEC("kprobe/__x64_sys_close")
int BPF_KPROBE(close, int fd) {
u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32;
// filter specific pid for simplicity
if (pid != 31114) {
return 0;
}
// debug fd arg (expected to be equal to fd returned on accept4)
bpf_printk("closed pid=%d fd=%d", pid, fd);
return 0;
}
结果(见意想不到的 fd=4
与 fd=15761240
差异):
$ cat /sys/kernel/debug/tracing/trace_pipe
main-31114 [001] d... 9069.254408: bpf_trace_printk: opened pid=31114 fd=4
main-31114 [001] d... 9069.321946: bpf_trace_printk: closed pid=31114 fd=15761240
我尝试更改 vmlinux.h
:首先使用 libbbpf-bootstrap 提供的 vmlinux.h
,然后使用实例 OS 中的“本地”vmlinux.h
] 内核和两种方式我都遇到了上面的问题。
还尝试以 BCC 方式 运行 相同的 bpf 程序(在 运行 时用 bcc 编译),声明的 kprobes 没有 BPF_KPROBE 宏,像这样:
int syscall__probe_close_entry(struct pt_regs *ctx, int fd) { ... }
它按预期工作:fd=4
在所有调试点。
是内核中的 BPF_KPROBE 宏 bug/incompatibility 还是我遗漏了什么?
由@anakryiko 解决here
那个__x64_sys_close()
实际上只有一个输入参数,那就是struct pt_regs *
,它包含了所有的系统调用输入参数。所以你必须做这样的事情才能访问输入参数:
SEC("kprobe/__x64_sys_close")
int BPF_KPROBE(do_sys_close, struct pt_regs *regs)
{
pid_t pid;
int fd;
fd = PT_REGS_PARM1_CORE(regs);
pid = bpf_get_current_pid_tgid() >> 32;
bpf_printk("KPROBE ENTRY pid = %d, fd = %d\n", pid, fd);
return 0;
}
添加特定于系统调用的 kprobe/kretprobe 宏可能是个好主意,因为这是一个常见问题。添加了 libbpf/libbpf#425 以跟踪它。
在使用 libbpf-bootstrap 时,我得到了 kprobe 系统调用的意外(和奇怪)函数参数。例如,对于带有 int close(inf fd)
签名的 close
系统调用上的 kprobe,我得到了巨大的 fd
值,如 fd=15761240
,而预期的是小整数,如 fd=4
。转载于 Debian 11 x64 (kernel 5.10.0-7-amd64)
和 Ubuntu 21.10 x64 (kernel ~5.13)
。
调试代码:
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
char LICENSE[] SEC("license") = "Dual BSD/GPL";
// accept4 syscall
// int accept4(int sockfd, struct sockaddr *restrict addr, socklen_t *restrict addrlen);
SEC("kretprobe/__x64_sys_accept4")
int BPF_KRETPROBE(accept, int ret) {
u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32;
// filter specific pid for simplicity
if (pid != 31114 || ret < 0) {
return 0;
}
// debug returned file descriptor
bpf_printk("opened pid=%d fd=%d", pid, ret);
return 0;
}
// close syscall
// int close(int fd);
SEC("kprobe/__x64_sys_close")
int BPF_KPROBE(close, int fd) {
u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32;
// filter specific pid for simplicity
if (pid != 31114) {
return 0;
}
// debug fd arg (expected to be equal to fd returned on accept4)
bpf_printk("closed pid=%d fd=%d", pid, fd);
return 0;
}
结果(见意想不到的 fd=4
与 fd=15761240
差异):
$ cat /sys/kernel/debug/tracing/trace_pipe
main-31114 [001] d... 9069.254408: bpf_trace_printk: opened pid=31114 fd=4
main-31114 [001] d... 9069.321946: bpf_trace_printk: closed pid=31114 fd=15761240
我尝试更改 vmlinux.h
:首先使用 libbbpf-bootstrap 提供的 vmlinux.h
,然后使用实例 OS 中的“本地”vmlinux.h
] 内核和两种方式我都遇到了上面的问题。
还尝试以 BCC 方式 运行 相同的 bpf 程序(在 运行 时用 bcc 编译),声明的 kprobes 没有 BPF_KPROBE 宏,像这样:
int syscall__probe_close_entry(struct pt_regs *ctx, int fd) { ... }
它按预期工作:fd=4
在所有调试点。
是内核中的 BPF_KPROBE 宏 bug/incompatibility 还是我遗漏了什么?
由@anakryiko 解决here
那个__x64_sys_close()
实际上只有一个输入参数,那就是struct pt_regs *
,它包含了所有的系统调用输入参数。所以你必须做这样的事情才能访问输入参数:
SEC("kprobe/__x64_sys_close")
int BPF_KPROBE(do_sys_close, struct pt_regs *regs)
{
pid_t pid;
int fd;
fd = PT_REGS_PARM1_CORE(regs);
pid = bpf_get_current_pid_tgid() >> 32;
bpf_printk("KPROBE ENTRY pid = %d, fd = %d\n", pid, fd);
return 0;
}
添加特定于系统调用的 kprobe/kretprobe 宏可能是个好主意,因为这是一个常见问题。添加了 libbpf/libbpf#425 以跟踪它。