我正在 Ubuntu 机器上开发 eBPF 程序:
$ uname -a
Linux ubuntu-bionic 4.18.0-16-generic #17~18.04.1-Ubuntu SMP Tue Feb 12 13:35:51 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
Run Code Online (Sandbox Code Playgroud)
为此,我需要bpf.h
许多定义以及bpf_helpers.h
辅助函数定义。我安装了一个带有标题的新内核:
apt-get update -y
apt-get install -y linux-image-4.18.0-16-generic linux-headers-4.18.0-16-generic
Run Code Online (Sandbox Code Playgroud)
标头包括bpf.h
:
$ find /usr/src/linux-headers-4.18.0-16 -name bpf.h
/usr/src/linux-headers-4.18.0-16/include/uapi/linux/bpf.h
/usr/src/linux-headers-4.18.0-16/include/linux/bpf.h
Run Code Online (Sandbox Code Playgroud)
但不是bpf_helpers.h
:
$ find /usr/src/linux-headers-4.18.0-16 -name bpf_helpers.h
Run Code Online (Sandbox Code Playgroud)
如何为我的内核获取此文件?为什么它不包含在分发标头中?
我可以签出特定版本的 Linux 内核或从master获取文件,但发行版可能会对上游进行更改,这让我这样做感到不舒服。
我正在运行一个 docker 容器,用于监控 Centos 7 服务器中的其他容器。由于 SELinux 默认启用,因此当它使用以下信息调用任何 bpf 操作时,它会阻止我的监控进程:
type=AVC msg=audit: avc: denied { map_create } for
pid=16739 comm="monitor" scontext=system_u:system_r:spc_t:s0
tcontext=system_u:system_r:spc_t:s0 tclass=bpf permissive=0
Run Code Online (Sandbox Code Playgroud)
我正在使用这样的 test-bpf.c 程序
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <linux/bpf.h>
#include <unistd.h>
#include <sys/syscall.h>
int main() {
union bpf_attr attr = {
.map_type = BPF_MAP_TYPE_HASH,
.key_size = 4,
.value_size = 4,
.max_entries = 256,
};
int ret = syscall(__NR_bpf, BPF_MAP_CREATE, &attr, 120);
fprintf(stderr, "ret = %d (%s)\n", ret, strerror((ret > 0) ? 0 : ret)); …
Run Code Online (Sandbox Code Playgroud) 是否有一个BPF表达式只能捕获 arp-reply 数据包?目前,我正在使用 Pcap4J 和以下 BPF 表达式:
arp 和 dst 主机主机和以太网 dst mac
其中host是我的设备的 IP 地址,mac是我的主网络接口的 MAC 地址。不幸的是,当捕获数据包时,该过滤器也允许捕获 ARP 广播请求,因此我必须采取额外的步骤来检查 ARP 标头的操作字段是否为 2 而不是 1。
是否可以编写一个通用的 EBPF 程序来读取所有用户空间程序的未加密 HTTPS 请求和响应主体?
据我了解,EBPF 处理网络第 2、3 和 4 层的数据包。HTTPS 有效负载在这些数据包中加密,因此 EBPF 可以读取数据包元数据,但不能读取构成 HTTPS 请求/响应的有效负载?
这样做是将日志记录添加到用户空间程序的唯一方法吗?
eBPF 已成为轻松快速地监控流程的重要工具。然而,我无法找到如何计算探针本身对性能的影响。我确信如果我挂钩每个系统调用并在地图中推送一些信息,一定会产生一些影响,没有什么是免费的,但是我将如何正确计算这种增加的延迟?
我想到的唯一解决方案是在探测器处于活动状态和不活动状态的情况下多次运行相同的程序,并检查系统执行时间差异,但在我看来,这会受到各种因素的影响,这些因素可能会增加很多差异因此不会给出非常可靠的结果。
如何使用Berkeley Packet Filter(BPF)过滤内核中的函数参数?该函数应该是任何非内联函数,而不仅仅是系统调用.此外,最好能够取消引用函数参数中的指针以进行验证.
我搜索了互联网,但找不到任何用例.大多数材料仅描述了如何使用seccomp/seccomp-BPF.
似乎整合了eBPF和kprobe/jprobe来实现挂钩.但我无法在网上找到一个好的例子.
为了模拟某些行为,我想将探测附加到系统调用,并在传递某些参数时修改返回值.或者,在函数处理之前修改函数的参数也就足够了.
这可能与BPF有关吗?
我正在寻找 eBPF 的示例来编写 seccomp 过滤器,但我找不到。有人能告诉我是否可以使用 eBPF 编写 seccomp 过滤器吗?
中是如何"%p"
实施的bpf_trace_printk
?看起来很不一样printf
。
#include <uapi/linux/ptrace.h>
int print_args(struct pt_regs *ctx) {
void *ptr = (void*)PT_REGS_PARM1(ctx);
bpf_trace_printk("args: %lx %p %ld\n", ptr, ptr, ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我使用这个 eBPF 程序来跟踪一个函数的参数。参数的类型是指向某个结构的指针。
一种输出是:
args: 7ffde047d6c4 00000000ec7e9023 140728366257860
我们可以注意到 的输出"%p"
非常奇怪。如果我们使用标准 C 程序来检查输出:
#include <stdio.h>
int main() {
void *ptr = (void*)0x7ffde047d6c4;
printf("args: %lx %p %ld\n", ptr, ptr, ptr);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我们将获得: args: 7ffde047d6c4 0x7ffde047d6c4 140728366257860
sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &f, sizeof (f))
Run Code Online (Sandbox Code Playgroud)
使用这个简单的 BPF/LPF 附加代码,当我尝试在套接字上接收数据包时,会得到一些与过滤器不匹配的错误数据包。在我调用setsockopt() 之前,这些数据包似乎已进入套接字。
似乎应该首先创建 AF_PACKET SOCK_RAW 套接字,然后附加过滤器,然后刷新套接字以摆脱那些错误的数据包。
所以问题是,如何刷新这些数据包?
bpf ×10
ebpf ×6
linux ×4
c ×2
linux-kernel ×2
seccomp ×2
arp ×1
centos ×1
chroot ×1
docker ×1
ethernet ×1
header-files ×1
https ×1
java ×1
kernel ×1
monitoring ×1
pcap4j ×1
performance ×1
raw-sockets ×1
sandbox ×1
selinux ×1
sockets ×1
system-calls ×1