You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

追踪__sys_bpf时bpfptr_t参数获取异常及相关问题求助

问题分析与解决方案

1. 直接接收bpfptr_t参数编译报错的原因

bpfptr_t在你使用的5.15内核中是sockptr_t的别名,它是一个结构体而非单纯的指针类型,定义大致如下:

typedef struct {
    unsigned long ptr;
    int is_user;
} sockptr_t;

kprobe探针函数的参数默认以unsigned long类型传递原函数参数,但结构体类型无法直接用unsigned long初始化,因此编译时会报类型不兼容错误。而PT_REGS_PARM2获取的是寄存器中的单个值(仅对应结构体的部分成员),无法直接赋值给bpfptr_t结构体变量,自然无法成功。

2. 第三个参数(bpf_attr大小)始终为0的解决方法

问题核心在于参数的寄存器偏移:
x86_64的System V ABI中,当函数参数是大小≤16字节的结构体时,会用多个寄存器传递其成员。bpfptr_t大小为12字节,会占用rsi(存储ptr)和rdx(存储is_user)两个寄存器,因此原函数__sys_bpf的第三个参数size会被放到rcx寄存器,对应kprobe中的PT_REGS_PARM4(ctx)而非PT_REGS_PARM3(ctx)。

正确的参数读取代码示例:

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

SEC("kprobe/__sys_bpf")
int kprobe___sys_bpf(struct pt_regs *ctx)
{
    int cmd = PT_REGS_PARM1(ctx);
    struct sockptr_t uattr;
    unsigned int size;

    // 直接从寄存器读取结构体成员
    uattr.ptr = PT_REGS_PARM2(ctx);
    uattr.is_user = (int)PT_REGS_PARM3(ctx);
    // 读取第三个参数size,对应rcx寄存器
    size = PT_REGS_PARM4(ctx);

    // 验证输出(可通过bpf_printk查看)
    bpf_printk("cmd: %d, uattr.ptr: %lx, uattr.is_user: %d, size: %u\n", 
               cmd, uattr.ptr, uattr.is_user, size);

    return 0;
}

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

执行上述代码即可正确获取第三个参数的有效值。

3. 为何追踪__sys_bpf必须用bpf_probe_read_kernel,其他函数可以直接接收参数

这取决于原函数参数的类型特性:

  • 若原函数参数是标量类型(如int、unsigned long)或指针类型(本质是unsigned long),这些类型可直接与kprobe传递的unsigned long参数兼容,因此能直接在探针函数参数中接收。
  • 但__sys_bpf的第二个参数是结构体类型,结构体作为函数参数传递时,要么占用多个寄存器,要么通过栈传递,无法用单个unsigned long表示完整的结构体内容。此时必须通过bpf_probe_read_kernel(或直接读取对应寄存器组合)来获取结构体的完整成员,才能正确解析参数。

内容的提问来源于stack exchange,提问作者luke zou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 10:05:23