“无效的bpf_context访问”试图读取“ regs”参数时

发布于 2025-02-11 22:35:49 字数 3197 浏览 2 评论 0 原文

取决于/sys/kernel/btf/vmlinux 中的SYSCALL的定义方式,阅读 struct pt_regs *regs fentry/fexit Traces的参数 Invalid bpf_context Access 错误:

SEC("fentry/__x64_sys_recvfrom")
int BPF_PROG(fentry_syscall, struct pt_regs *regs) {
  struct event t;

  bpf_get_current_comm(t.comm, TASK_COMM_LEN);

  u64 id = bpf_get_current_pid_tgid();
  t.pid = id >> 32;

  // This causes an error on some environment.
  t.fd = PT_REGS_PARM1_CORE(regs);

  bpf_printk("comm: %s, pid: %d, fd: %d", t.comm, t.pid, t.fd);

  return 0;
$ sudo ./output
2022/07/01 03:33:01 loading objects: field FentrySyscall: program fentry_syscall: load program: permission denied:
        arg#0 type is not a struct
        Unrecognized arg#0 type PTR
        ; int BPF_PROG(fentry_syscall, struct pt_regs *regs) {
        0: (79) r6 = *(u64 *)(r1 +0)
        func '__x64_sys_recvfrom' arg0 type FWD is not a struct
        invalid bpf_context access off=0 size=8
        processed 1 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

当定义为btf的参数称为 fwd

$ bpftool btf dump file /sys/kernel/btf/vmlinux format raw
...
[13362] FWD 'pt_regs' fwd_kind=struct
[13363] CONST '(anon)' type_id=13362
[13364] PTR '(anon)' type_id=13363
[13365] FUNC_PROTO '(anon)' ret_type_id=36 vlen=1
        '__unused' type_id=13364
...
[13608] FUNC '__x64_sys_recvmsg' type_id=13365 linkage=static
...

同时,没有错误的SYSCALLS/环境具有混凝土类型的定义,例如:

$ bpftool btf dump file /sys/kernel/btf/vmlinux format raw
[1] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64 encoding=(none)
...
[226] STRUCT 'pt_regs' size=168 vlen=21
        'r15' type_id=1 bits_offset=0
        'r14' type_id=1 bits_offset=64
        'r13' type_id=1 bits_offset=128
        'r12' type_id=1 bits_offset=192
        'bp' type_id=1 bits_offset=256
        'bx' type_id=1 bits_offset=320
        'r11' type_id=1 bits_offset=384
        'r10' type_id=1 bits_offset=448
        'r9' type_id=1 bits_offset=512
        'r8' type_id=1 bits_offset=576
        'ax' type_id=1 bits_offset=640
        'cx' type_id=1 bits_offset=704
        'dx' type_id=1 bits_offset=768
        'si' type_id=1 bits_offset=832
        'di' type_id=1 bits_offset=896
        'orig_ax' type_id=1 bits_offset=960
        'ip' type_id=1 bits_offset=1024
        'cs' type_id=1 bits_offset=1088
        'flags' type_id=1 bits_offset=1152
        'sp' type_id=1 bits_offset=1216
        'ss' type_id=1 bits_offset=1280
...
[5183] CONST '(anon)' type_id=226
...
[5189] PTR '(anon)' type_id=5183
...
[5321] FUNC_PROTO '(anon)' ret_type_id=42 vlen=1
        '__unused' type_id=5189
...
[17648] FUNC '__x64_sys_recvmsg' type_id=5321 linkage=static
...

我已经在几个分布和几个分布中进行了测试, 这似乎会发生。发现如何定义 regs 取决于分布/内核/syscall组合。为什么它们如此复杂?如何避免此错误,并使我的EBPF程序在任何(最新的)Linux环境上运行。

我已经创建了一个 github repo for这个问题

Depending on how the syscall is defined in /sys/kernel/btf/vmlinux, reading struct pt_regs *regs parameter for fentry/fexit traces causes invalid bpf_context access error:

SEC("fentry/__x64_sys_recvfrom")
int BPF_PROG(fentry_syscall, struct pt_regs *regs) {
  struct event t;

  bpf_get_current_comm(t.comm, TASK_COMM_LEN);

  u64 id = bpf_get_current_pid_tgid();
  t.pid = id >> 32;

  // This causes an error on some environment.
  t.fd = PT_REGS_PARM1_CORE(regs);

  bpf_printk("comm: %s, pid: %d, fd: %d", t.comm, t.pid, t.fd);

  return 0;
$ sudo ./output
2022/07/01 03:33:01 loading objects: field FentrySyscall: program fentry_syscall: load program: permission denied:
        arg#0 type is not a struct
        Unrecognized arg#0 type PTR
        ; int BPF_PROG(fentry_syscall, struct pt_regs *regs) {
        0: (79) r6 = *(u64 *)(r1 +0)
        func '__x64_sys_recvfrom' arg0 type FWD is not a struct
        invalid bpf_context access off=0 size=8
        processed 1 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0

This seems to occur when the parameter defined as BTF is declared as FWD:

$ bpftool btf dump file /sys/kernel/btf/vmlinux format raw
...
[13362] FWD 'pt_regs' fwd_kind=struct
[13363] CONST '(anon)' type_id=13362
[13364] PTR '(anon)' type_id=13363
[13365] FUNC_PROTO '(anon)' ret_type_id=36 vlen=1
        '__unused' type_id=13364
...
[13608] FUNC '__x64_sys_recvmsg' type_id=13365 linkage=static
...

Meanwhile, syscalls/environments with no errors have a concrete type definition like:

$ bpftool btf dump file /sys/kernel/btf/vmlinux format raw
[1] INT 'long unsigned int' size=8 bits_offset=0 nr_bits=64 encoding=(none)
...
[226] STRUCT 'pt_regs' size=168 vlen=21
        'r15' type_id=1 bits_offset=0
        'r14' type_id=1 bits_offset=64
        'r13' type_id=1 bits_offset=128
        'r12' type_id=1 bits_offset=192
        'bp' type_id=1 bits_offset=256
        'bx' type_id=1 bits_offset=320
        'r11' type_id=1 bits_offset=384
        'r10' type_id=1 bits_offset=448
        'r9' type_id=1 bits_offset=512
        'r8' type_id=1 bits_offset=576
        'ax' type_id=1 bits_offset=640
        'cx' type_id=1 bits_offset=704
        'dx' type_id=1 bits_offset=768
        'si' type_id=1 bits_offset=832
        'di' type_id=1 bits_offset=896
        'orig_ax' type_id=1 bits_offset=960
        'ip' type_id=1 bits_offset=1024
        'cs' type_id=1 bits_offset=1088
        'flags' type_id=1 bits_offset=1152
        'sp' type_id=1 bits_offset=1216
        'ss' type_id=1 bits_offset=1280
...
[5183] CONST '(anon)' type_id=226
...
[5189] PTR '(anon)' type_id=5183
...
[5321] FUNC_PROTO '(anon)' ret_type_id=42 vlen=1
        '__unused' type_id=5189
...
[17648] FUNC '__x64_sys_recvmsg' type_id=5321 linkage=static
...

I've tested on several distributions and found that how the regs is defined depends on the distribution/kernel/syscall combination. Why are they so complicated? How can I avoid this error and make my eBPF program run on any (latest) Linux environments.

I've created a GitHub repo for this issue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

忆依然 2025-02-18 22:35:49

这本质上是一个错误,已在Linux 5.15.78中固定。

日志所说的:

    With just the forward declaration of the 'struct pt_regs' in
    syscall_wrapper.h, the syscall stub functions:
    
      __[x64|ia32]_sys_*(struct pt_regs *regs)
    
    will have different definition of 'regs' argument in BTF data
    based on which object file they are defined in.
    
    If the syscall's object includes 'struct pt_regs' definition,
    the BTF argument data will point to a 'struct pt_regs' record,
    like:
    
      [226] STRUCT 'pt_regs' size=168 vlen=21
             'r15' type_id=1 bits_offset=0
             'r14' type_id=1 bits_offset=64
             'r13' type_id=1 bits_offset=128
      ...
    
    If not, it will point to a fwd declaration record:
    
      [15439] FWD 'pt_regs' fwd_kind=struct
    
    and make bpf tracing program hooking on those functions unable
    to access fields from 'struct pt_regs'.
    
    Include asm/ptrace.h directly in syscall_wrapper.h to make sure all
    syscalls see 'struct pt_regs' definition. This then results in BTF for
    '__*_sys_*(struct pt_regs *regs)' functions to point to the actual
    struct, not just the forward declaration.

这是提交 在 asm/ptrace.h 带有实际定义 #include< asm/ptrace.h> 解决了问题。

This is essentially a bug and has been fixed in Linux 5.15.78.

This is what the commit log says:

    With just the forward declaration of the 'struct pt_regs' in
    syscall_wrapper.h, the syscall stub functions:
    
      __[x64|ia32]_sys_*(struct pt_regs *regs)
    
    will have different definition of 'regs' argument in BTF data
    based on which object file they are defined in.
    
    If the syscall's object includes 'struct pt_regs' definition,
    the BTF argument data will point to a 'struct pt_regs' record,
    like:
    
      [226] STRUCT 'pt_regs' size=168 vlen=21
             'r15' type_id=1 bits_offset=0
             'r14' type_id=1 bits_offset=64
             'r13' type_id=1 bits_offset=128
      ...
    
    If not, it will point to a fwd declaration record:
    
      [15439] FWD 'pt_regs' fwd_kind=struct
    
    and make bpf tracing program hooking on those functions unable
    to access fields from 'struct pt_regs'.
    
    Include asm/ptrace.h directly in syscall_wrapper.h to make sure all
    syscalls see 'struct pt_regs' definition. This then results in BTF for
    '__*_sys_*(struct pt_regs *regs)' functions to point to the actual
    struct, not just the forward declaration.

Replacing a forward declaration struct pt_regs; in asm/ptrace.h with an actual definition #include <asm/ptrace.h> fixes the issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文