BPF 验证器在尝试访问 __sk_buff 成员时拒绝
BPF verifier rejects when try to access __sk_buff member
我正在尝试编写一个示例 eBPF 程序,它可以访问 __sk_buff 成员并将其转储到
/sys/kernel/debug/tracing/trace.
#include <uapi/linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
SEC("dump_skb_member")
int test_prog(struct __sk_buff *skb)
{
char fmt[] = "packet: local %u remote %u\n";
__u32 local_ip4 = bpf_htonl(skb->local_ip4);
__u32 remote_ip4 = bpf_htonl(skb->remote_ip4);
bpf_trace_printk(fmt, sizeof(fmt), local_ip4, remote_ip4);
return BPF_OK;
}
char _license[] SEC("license") = "GPL";
当我编译这段代码,并加载这个程序时
ip route add 192.168.56.104 encap bpf out obj sample.o section dump_skb_member dev enp0s8
抛出错误。
Prog section 'dump_skb_member' rejected: Permission denied (13)!
- Type: 11
- Instructions: 21 (0 over limit)
- License: GPL
Verifier analysis:
0: (b7) r2 = 685349
1: (63) *(u32 *)(r10 -8) = r2
2: (18) r2 = 0x2065746f6d657220
4: (7b) *(u64 *)(r10 -16) = r2
5: (18) r2 = 0x7525206c61636f6c
7: (7b) *(u64 *)(r10 -24) = r2
8: (18) r2 = 0x203a74656b636170
10: (7b) *(u64 *)(r10 -32) = r2
11: (61) r4 = *(u32 *)(r1 +92)
invalid bpf_context access off=92 size=4
processed 9 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
Error fetching program/map!
但是如果我不调用bpf_trace_printk转储成员,它可以加载。
我的问题是为什么错误是调用bpf_trace_printk?
引起的
错误 不是 由 bpf_trace_prink()
引起的,而是由 skb
访问引起的,只有当您调用 bpf_trace_printk()
.
您使用的 BPF_PROG_TYPE_LWT_OUT
类型的程序不允许访问 skb->local_ip4
和 skb->remote_ip4
。
查看内核代码:function that checks for valid access 对于这种类型 returns false 对于 skb
中的某些偏移量或范围:
case bpf_ctx_range_till(struct __sk_buff, family, local_port):
[...]
return false;
这对应local_ip4
和remote_ip4
are defined的范围:
struct __sk_buff {
[...]
/* Accessed by BPF_PROG_TYPE_sk_skb types from here to ... */
__u32 family;
__u32 remote_ip4; /* Stored in network byte order */
__u32 local_ip4; /* Stored in network byte order */
__u32 remote_ip6[4]; /* Stored in network byte order */
__u32 local_ip6[4]; /* Stored in network byte order */
__u32 remote_port; /* Stored in network byte order */
__u32 local_port; /* stored in host byte order */
/* ... here. */
当您删除对 bpf_trace_printk()
帮助程序的调用时,您的局部变量将不再需要,clang 会将您的代码编译出程序。尝试读取禁止偏移量不再是字节码的一部分,因此程序成功加载。
我正在尝试编写一个示例 eBPF 程序,它可以访问 __sk_buff 成员并将其转储到 /sys/kernel/debug/tracing/trace.
#include <uapi/linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
SEC("dump_skb_member")
int test_prog(struct __sk_buff *skb)
{
char fmt[] = "packet: local %u remote %u\n";
__u32 local_ip4 = bpf_htonl(skb->local_ip4);
__u32 remote_ip4 = bpf_htonl(skb->remote_ip4);
bpf_trace_printk(fmt, sizeof(fmt), local_ip4, remote_ip4);
return BPF_OK;
}
char _license[] SEC("license") = "GPL";
当我编译这段代码,并加载这个程序时
ip route add 192.168.56.104 encap bpf out obj sample.o section dump_skb_member dev enp0s8
抛出错误。
Prog section 'dump_skb_member' rejected: Permission denied (13)!
- Type: 11
- Instructions: 21 (0 over limit)
- License: GPL
Verifier analysis:
0: (b7) r2 = 685349
1: (63) *(u32 *)(r10 -8) = r2
2: (18) r2 = 0x2065746f6d657220
4: (7b) *(u64 *)(r10 -16) = r2
5: (18) r2 = 0x7525206c61636f6c
7: (7b) *(u64 *)(r10 -24) = r2
8: (18) r2 = 0x203a74656b636170
10: (7b) *(u64 *)(r10 -32) = r2
11: (61) r4 = *(u32 *)(r1 +92)
invalid bpf_context access off=92 size=4
processed 9 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
Error fetching program/map!
但是如果我不调用bpf_trace_printk转储成员,它可以加载。
我的问题是为什么错误是调用bpf_trace_printk?
引起的错误 不是 由 bpf_trace_prink()
引起的,而是由 skb
访问引起的,只有当您调用 bpf_trace_printk()
.
您使用的 BPF_PROG_TYPE_LWT_OUT
类型的程序不允许访问 skb->local_ip4
和 skb->remote_ip4
。
查看内核代码:function that checks for valid access 对于这种类型 returns false 对于 skb
中的某些偏移量或范围:
case bpf_ctx_range_till(struct __sk_buff, family, local_port):
[...]
return false;
这对应local_ip4
和remote_ip4
are defined的范围:
struct __sk_buff {
[...]
/* Accessed by BPF_PROG_TYPE_sk_skb types from here to ... */
__u32 family;
__u32 remote_ip4; /* Stored in network byte order */
__u32 local_ip4; /* Stored in network byte order */
__u32 remote_ip6[4]; /* Stored in network byte order */
__u32 local_ip6[4]; /* Stored in network byte order */
__u32 remote_port; /* Stored in network byte order */
__u32 local_port; /* stored in host byte order */
/* ... here. */
当您删除对 bpf_trace_printk()
帮助程序的调用时,您的局部变量将不再需要,clang 会将您的代码编译出程序。尝试读取禁止偏移量不再是字节码的一部分,因此程序成功加载。