英文:
Extract packet data using BPF from struct msghr
问题
以下是您的代码的翻译部分:
我正在尝试钩住sock_sendmsg并打印数据包数据。以下是我的代码。
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#define IP_169_254_169_254 0xFEA9FEA
#define TASK_COMM_LEN 128
SEC("fentry/sock_sendmsg")
int BPF_PROG(sock_sendmsg, struct socket *sock, struct msghdr *msg)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
char comm[128];
char pkt[128];
int contains_payload;
struct sock *sk = sock->sk;
if (sk->__sk_common.skc_daddr == IP_169_254_169_254)
{
const struct iovec *iov = msg->msg_iter.iov;
void *iovbase = iov->iov_base;
bpf_probe_read_str(&pkt, sizeof(pkt), iovbase);
if(pkt[0] == '我正在尝试钩住sock_sendmsg并打印数据包数据。以下是我的代码。
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#define IP_169_254_169_254 0xFEA9FEA
#define TASK_COMM_LEN 128
SEC("fentry/sock_sendmsg")
int BPF_PROG(sock_sendmsg, struct socket *sock, struct msghdr *msg)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
char comm[128];
char pkt[128];
int contains_payload;
struct sock *sk = sock->sk;
if (sk->__sk_common.skc_daddr == IP_169_254_169_254)
{
const struct iovec *iov = msg->msg_iter.iov;
void *iovbase = iov->iov_base;
bpf_probe_read_str(&pkt, sizeof(pkt), iovbase);
if(pkt[0] == '\0'){
contains_payload = 0;
}
else
{
contains_payload = 1;
}
bpf_get_current_comm(&comm, sizeof(comm));
bpf_printk("%d , %s, %d, %s", pid, comm, contains_payload, pkt);
}
return 0;
}
char _license[] SEC("license") = "GPL";
'){
contains_payload = 0;
}
else
{
contains_payload = 1;
}
bpf_get_current_comm(&comm, sizeof(comm));
bpf_printk("%d , %s, %d, %s", pid, comm, contains_payload, pkt);
}
return 0;
}
char _license[] SEC("license") = "GPL";
请注意,我已经将HTML编码的引号字符还原为正常的引号字符,以便代码在编译时不会出现问题。
至于代码中的问题,您提到在尝试使用 bpf_printk
打印 pkt
时出现问题。如果删除 bpf_printk
中的 pkt
,则能够打印出进程、comm 和 pkt 中的数据。此错误消息表明 BPF 程序加载失败,可能是因为数据结构的定义问题或其他原因导致加载失败。您需要仔细检查代码并确保类型定义和数据结构匹配正确。
如果您有关于特定问题的更多详细信息,可以提供给我,我会尽力提供进一步的指导。
英文:
I am trying to hook to sock_sendmsg and print the packet data. Here is my code.
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#define IP_169_254_169_254 0xFEA9FEA
#define TASK_COMM_LEN 128
SEC("fentry/sock_sendmsg")
int BPF_PROG(sock_sendmsg, struct socket *sock, struct msghdr *msg)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
char comm[128];
char pkt[128];
int contains_payload;
struct sock *sk = sock->sk;
if (sk->__sk_common.skc_daddr == IP_169_254_169_254)
{
const struct iovec * iov = msg->msg_iter.iov;
void *iovbase = iov->iov_base;
bpf_probe_read_str(&pkt, sizeof(pkt), iovbase);
if(pkt[0] == '#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
#include <bpf/bpf_core_read.h>
#define IP_169_254_169_254 0xFEA9FEA
#define TASK_COMM_LEN 128
SEC("fentry/sock_sendmsg")
int BPF_PROG(sock_sendmsg, struct socket *sock, struct msghdr *msg)
{
u32 pid = bpf_get_current_pid_tgid() >> 32;
char comm[128];
char pkt[128];
int contains_payload;
struct sock *sk = sock->sk;
if (sk->__sk_common.skc_daddr == IP_169_254_169_254)
{
const struct iovec * iov = msg->msg_iter.iov;
void *iovbase = iov->iov_base;
bpf_probe_read_str(&pkt, sizeof(pkt), iovbase);
if(pkt[0] == '\0'){
contains_payload = 0;
}
else
{
contains_payload = 1;
}
bpf_get_current_comm(&comm, sizeof(comm));
bpf_printk("%d , %s, %d, %s",pid,comm, contains_payload, pkt);
}
return 0;
}
char _license[] SEC("license") = "GPL";
'){
contains_payload = 0;
}
else
{
contains_payload = 1;
}
bpf_get_current_comm(&comm, sizeof(comm));
bpf_printk("%d , %s, %d, %s",pid,comm, contains_payload, pkt);
}
return 0;
}
char _license[] SEC("license") = "GPL";
The issue comes when i try to print pkt
using bpf_printk
. If I don't try to print it and remove it from bpf_printk
. I see the printed process, comm and that there is data in the pkt.
I wanted to know what I am doing wrong here and any guidance would be appreciated.
This is the crash data:
libbpf: loading object 'fentry_bpf' from buffer
libbpf: elf: section(3) fentry/sock_sendmsg, size 312, link 0, flags 6, type=1
libbpf: sec 'fentry/sock_sendmsg': found program 'sock_sendmsg' at insn offset 0 (0 bytes), code size 39 insns (312 bytes)
libbpf: elf: section(4) .relfentry/sock_sendmsg, size 16, link 23, flags 0, type=9
libbpf: elf: section(5) license, size 4, link 0, flags 3, type=1
libbpf: license of fentry_bpf is GPL
libbpf: elf: section(6) .maps, size 32, link 0, flags 3, type=1
libbpf: elf: section(7) .rodata, size 16, link 0, flags 2, type=1
libbpf: elf: section(14) .BTF, size 11492, link 0, flags 0, type=1
libbpf: elf: section(16) .BTF.ext, size 412, link 0, flags 0, type=1
libbpf: elf: section(18) .eh_frame, size 48, link 0, flags 2, type=1
libbpf: elf: skipping unrecognized data section(18) .eh_frame
libbpf: elf: section(19) .rel.eh_frame, size 16, link 23, flags 0, type=9
libbpf: elf: skipping relo section(19) .rel.eh_frame for section(18) .eh_frame
libbpf: elf: section(23) .symtab, size 244848, link 1, flags 0, type=2
libbpf: looking for externs among 10202 symbols...
libbpf: collected 0 externs total
libbpf: map 'imds_http_data': at sec_idx 6, offset 0.
libbpf: map 'imds_http_data': found type = 6.
libbpf: map 'imds_http_data': found key [8], sz = 4.
libbpf: map 'imds_http_data': found value [12], sz = 31884.
libbpf: map 'imds_http_data': found max_entries = 1.
libbpf: map 'fentry_b.rodata' (global data): at sec_idx 7, offset 0, flags 80.
libbpf: map 1 is "fentry_b.rodata"
libbpf: sec '.relfentry/sock_sendmsg': collecting relocation for section(3) 'fentry/sock_sendmsg'
libbpf: sec '.relfentry/sock_sendmsg': relo #0: insn #32 against '.rodata'
libbpf: prog 'sock_sendmsg': found data map 1 (fentry_b.rodata, sec 7, off 0) for insn 32
libbpf: loading kernel BTF '/sys/kernel/btf/vmlinux': 0
libbpf: map 'imds_http_data': created successfully, fd=4
libbpf: map 'fentry_b.rodata': created successfully, fd=5
libbpf: sec 'fentry/sock_sendmsg': found 4 CO-RE relocations
libbpf: CO-RE relocating [22] struct socket: found target candidate [3213] struct socket in [vmlinux]
libbpf: prog 'sock_sendmsg': relo #0: <byte_off> [22] struct socket.sk (0:4 @ offset 24)
libbpf: prog 'sock_sendmsg': relo #0: matching candidate #0 <byte_off> [3213] struct socket.sk (0:4 @ offset 24)
libbpf: prog 'sock_sendmsg': relo #0: patched insn #4 (LDX/ST/STX) off 24 -> 24
libbpf: CO-RE relocating [58] struct sock: found target candidate [2658] struct sock in [vmlinux]
libbpf: prog 'sock_sendmsg': relo #1: <byte_off> [58] struct sock.__sk_common.skc_daddr (0:0:0:1:0 @ offset 0)
libbpf: prog 'sock_sendmsg': relo #1: matching candidate #0 <byte_off> [2658] struct sock.__sk_common.skc_daddr (0:0:0:1:0 @ offset 0)
libbpf: prog 'sock_sendmsg': relo #1: patched insn #5 (LDX/ST/STX) off 0 -> 0
libbpf: CO-RE relocating [168] struct msghdr: found target candidate [2682] struct msghdr in [vmlinux]
libbpf: prog 'sock_sendmsg': relo #2: <byte_off> [168] struct msghdr.msg_iter.iov (0:2:3:0 @ offset 40)
libbpf: prog 'sock_sendmsg': relo #2: matching candidate #0 <byte_off> [2682] struct msghdr.msg_iter.iov (0:2:3:0 @ offset 40)
libbpf: prog 'sock_sendmsg': relo #2: patched insn #9 (LDX/ST/STX) off 40 -> 40
libbpf: CO-RE relocating [185] struct iovec: found target candidate [1695] struct iovec in [vmlinux]
libbpf: prog 'sock_sendmsg': relo #3: <byte_off> [185] struct iovec.iov_base (0:0 @ offset 0)
libbpf: prog 'sock_sendmsg': relo #3: matching candidate #0 <byte_off> [1695] struct iovec.iov_base (0:0 @ offset 0)
libbpf: prog 'sock_sendmsg': relo #3: patched insn #10 (LDX/ST/STX) off 0 -> 0
libbpf: prog 'sock_sendmsg': BPF program load failed: Invalid argument
libbpf: prog 'sock_sendmsg': -- BEGIN PROG LOAD LOG --
arg#0 type is not a struct
Unrecognized arg#0 type PTR
; int BPF_PROG(sock_sendmsg, struct socket *sock, struct msghdr *msg)
0: (79) r7 = *(u64 *)(r1 +8)
func 'sock_sendmsg' arg1 has btf_id 2682 type STRUCT 'msghdr'
1: (79) r8 = *(u64 *)(r1 +0)
func 'sock_sendmsg' arg0 has btf_id 3213 type STRUCT 'socket'
; u32 pid = bpf_get_current_pid_tgid() >> 32;
2: (85) call bpf_get_current_pid_tgid#14
3: (bf) r6 = r0
; struct sock *sk = sock->sk;
4: (79) r1 = *(u64 *)(r8 +24)
; if (sk->__sk_common.skc_daddr == IP_169_254_169_254)
5: (61) r1 = *(u32 *)(r1 +0)
6: (18) r2 = 0xfea9fea9
; if (sk->__sk_common.skc_daddr == IP_169_254_169_254)
8: (5d) if r1 != r2 goto pc+28
R0_w=inv(id=1) R1_w=inv4272553641 R2_w=inv4272553641 R6_w=inv(id=1) R7_w=ptr_msghdr(id=0,off=0,imm=0) R8_w=ptr_socket(id=0,off=0,imm=0) R10=fp0
; const struct iovec * iov = msg->msg_iter.iov;
9: (79) r1 = *(u64 *)(r7 +40)
; void *iovbase = iov->iov_base;
10: (79) r3 = *(u64 *)(r1 +0)
11: (bf) r7 = r10
; const struct iovec * iov = msg->msg_iter.iov;
12: (07) r7 += -256
; bpf_probe_read_str(&pkt, sizeof(pkt), iovbase);
13: (bf) r1 = r7
14: (b7) r2 = 128
15: (85) call bpf_probe_read_str#45
last_idx 15 first_idx 0
regs=4 stack=0 before 14: (b7) r2 = 128
; if(pkt[0] == '\0'){
16: (71) r9 = *(u8 *)(r10 -256)
17: (bf) r8 = r10
; const struct iovec * iov = msg->msg_iter.iov;
18: (07) r8 += -128
; bpf_get_current_comm(&comm, sizeof(comm));
19: (bf) r1 = r8
20: (b7) r2 = 128
21: (85) call bpf_get_current_comm#16
last_idx 21 first_idx 16
regs=4 stack=0 before 20: (b7) r2 = 128
22: (b7) r1 = 1
; if(pkt[0] == '\0'){
23: (55) if r9 != 0x0 goto pc+1
R0_w=inv(id=0) R1_w=inv1 R6=inv(id=1) R7=fp-256 R8_w=fp-128 R9_w=inv0 R10=fp0 fp-8=mmmmmmmm fp-16=mmmmmmmm fp-24=mmmmmmmm fp-32=mmmmmmmm fp-40=mmmmmmmm fp-48=mmmmmmmm fp-56=mmmmmmmm fp-64=mmmmmmmm fp-72=mmmmmmmm fp-80=mmmmmmmm fp-88=mmmmmmmm fp-96=mmmmmmmm fp-104=mmmmmmmm fp-112=mmmmmmmm fp-120=mmmmmmmm fp-128=mmmmmmmm fp-136=mmmmmmmm fp-144=mmmmmmmm fp-152=mmmmmmmm fp-160=mmmmmmmm fp-168=mmmmmmmm fp-176=mmmmmmmm fp-184=mmmmmmmm fp-192=mmmmmmmm fp-200=mmmmmmmm fp-208=mmmmmmmm fp-216=mmmmmmmm fp-224=mmmmmmmm fp-232=mmmmmmmm fp-240=mmmmmmmm fp-248=mmmmmmmm fp-256=mmmmmmmm
24: (b7) r1 = 0
; bpf_printk("%d , %s, %d, %s",pid,comm, contains_payload, pkt);
25: (7b) *(u64 *)(r10 -264) = r7
26: (7b) *(u64 *)(r10 -272) = r1
last_idx 26 first_idx 25
regs=2 stack=0 before 25: (7b) *(u64 *)(r10 -264) = r7
R0_w=inv(id=0) R1_rw=invP0 R6=inv(id=1) R7_r=fp-256 R8_w=fp-128 R9_w=inv0 R10=fp0 fp-8=mmmmmmmm fp-16=mmmmmmmm fp-24=mmmmmmmm fp-32=mmmmmmmm fp-40=mmmmmmmm fp-48=mmmmmmmm fp-56=mmmmmmmm fp-64=mmmmmmmm fp-72=mmmmmmmm fp-80=mmmmmmmm fp-88=mmmmmmmm fp-96=mmmmmmmm fp-104=mmmmmmmm fp-112=mmmmmmmm fp-120=mmmmmmmm fp-128=mmmmmmmm fp-136=mmmmmmmm fp-144=mmmmmmmm fp-152=mmmmmmmm fp-160=mmmmmmmm fp-168=mmmmmmmm fp-176=mmmmmmmm fp-184=mmmmmmmm fp-192=mmmmmmmm fp-200=mmmmmmmm fp-208=mmmmmmmm fp-216=mmmmmmmm fp-224=mmmmmmmm fp-232=mmmmmmmm fp-240=mmmmmmmm fp-248=mmmmmmmm fp-256=mmmmmmmm
parent didn't have regs=2 stack=0 marks
last_idx 24 first_idx 16
regs=2 stack=0 before 24: (b7) r1 = 0
27: (7b) *(u64 *)(r10 -280) = r8
; u32 pid = bpf_get_current_pid_tgid() >> 32;
28: (77) r6 >>= 32
; bpf_printk("%d , %s, %d, %s",pid,comm, contains_payload, pkt);
29: (7b) *(u64 *)(r10 -288) = r6
30: (bf) r3 = r10
31: (07) r3 += -288
32: (18) r1 = 0xffff8886d4b76110
34: (b7) r2 = 16
35: (b7) r4 = 32
36: (85) call unknown#177
invalid func unknown#177
processed 35 insns (limit 1000000) max_states_per_insn 0 total_states 2 peak_states 2 mark_read 2
-- END PROG LOAD LOG --
libbpf: prog 'sock_sendmsg': failed to load: -22
libbpf: failed to load object 'fentry_bpf'
libbpf: failed to load BPF skeleton 'fentry_bpf': -22
Failed to open BPF skeleton
答案1
得分: 1
bpf_printk
是由 libbpf 定义的宏,根据您想要打印的参数数量选择 bpf_trace_printk
或 bpf_trace_vprintk
。
BPF 辅助函数调用总共限制为 5 个参数,前两个参数被fmt
和sizeof(fmt)
占用,因此使用可变参数的 bpf_trace_printk
只能接受最多 3 个变量。
bpf_trace_vprintk
辅助函数在内核版本 v5.16 中引入,它接受参数数组而不是可变参数,可以打印更多的参数。
因为您在以下代码中记录了 4 个变量:
bpf_printk("%d , %s, %d, %s", pid, comm, contains_payload, pkt);
所以选择了 bpf_trace_vprintk
辅助函数。但是您可能正在运行一个不支持此辅助函数的较旧的内核,导致如下错误:
36: (85) call unknown#177
invalid func unknown#177
因此,请将每个 bpf_printf
记录的变量数量减少到 <= 3,或者升级您的内核至 >= v5.16。
英文:
bpf_printk
is a macro defined by libbpf which picks between the bpf_trace_printk
and bpf_trace_vprintk
depending on the amount of arguments you want to print.
BPF helper calls are limited to 5 arguments total, the first 2 are taken up by fmt
and sizeof(fmt)
so the bpf_trace_printk
which uses varadic arguments can only take up to 3 variables.
The bpf_trace_vprintk
helper function was introduced in kernel version v5.16 and takes an array of parameters instead of varatic arguments which allows you to print a larger amount of arguments.
Because you are logging 4 variables in
bpf_printk("%d , %s, %d, %s",pid,comm, contains_payload, pkt);
The bpf_trace_vprintk
helper is picked. But you are likely running an older kernel which doesn't support this helper resulting in
36: (85) call unknown#177
invalid func unknown#177
So reduce the amount of variables logged per bpf_printf
to <= 3 or update your kernel to >=v5.16
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论