介绍
eBPF 程序监听从内核发出的事件,具体取决于使用的钩子。该技术自 Linux 版本以来就已开发出来,几乎每个后续版本都引入了新功能,例如新型程序和映射。每个内核版本支持的功能的完整列表可以在网站上找到:https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md。3.15
如您所见,第一个版本和当前版本之间存在很大的飞跃。如何确保在向应用程序添加新的 eBPF 功能时没有超出受支持的版本?如果可以选择在最流行或所需的内核版本上测试您的应用程序,将会很有帮助。3.x
6.x
可能性
要跨多个版本的 Linux 评估 eBPF 应用程序,我们需要单独安装操作系统,有机会在那里建立一个应用程序并做一些准备好的测试。我们有什么样的选择?
少量磁盘分区,每个分区都安装了其他操作系统
在公有云上建立具有各种内核的虚拟机
使用仿真工具运行客户机操作系统,如 QEMU
第一个选项不是很方便。我们需要为安装分配大量的本地磁盘容量。测试需要重新启动计算机才能在内核版本之间切换,这使得该过程非常耗时且在工作流程中具有挑战性。CI/CD
第二个选项比第一个好得多。我们不需要分配私人空间,可以与进程集成,并允许我们仅在需要时调用特定的虚拟机。这种方法的缺点是虚拟机处于运行状态时的成本、使用各种操作系统和 VM 大小准备的映像。CI/CD
第三个选项听起来最好:在一台且仅一台计算机上运行测试,并模拟其他内核版本的来宾操作系统。无需分配本地或公共资源,也不会产生额外费用。
仿真准备
为了模拟来宾操作系统,我们将使用开源工具 QEMU (https://www.qemu.org/)。QEMU 在 run 命令期间需要两个重要选项:内核和文件系统映像。
内核镜像
您需要执行几个步骤来编译内核映像以进行测试。第一个是选择特定版本。我的建议是至少使用长期支持版本并从网站下载它们:https://www.kernel.org/
接下来是准备配置文件。构建内核需要此文件,我们将进一步执行此操作。通过更改该文件中的属性,您可以修改系统配置,并且需要根据您的要求对其进行调整。根据 k8spacket 示例,我们需要启用一些功能:
# new config based on defaults for the current ARCH
make defconfig
# Rely on the default DWARF (debugging information file format) toolchain's version
./scripts/config --set-val CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT y
# Enable the bpf() system call that allows to manipulate BPF programs and maps in kernel
./scripts/config --set-val CONFIG_BPF_SYSCALL y
# Compile kernel with debug info, autoset by CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT on 6.x kernels
./scripts/config --set-val CONFIG_DEBUG_INFO y
# Generate BTF type information from DWARF debug info
./scripts/config --set-val CONFIG_DEBUG_INFO_BTF y
# enable network classification, autoset by CONFIG_NET_CLS_BPF
#./scripts/config --set-val CONFIG_NET_CLS_ACT y
# BPF-based classifier
./scripts/config --set-val CONFIG_NET_CLS_BPF y
# Ingress/classifier-action qdisc
./scripts/config --set-val CONFIG_NET_SCH_INGRESS y
# regenerate config based on new values and defaults
make olddefconfig
请注意选择特定配置。他们中的一些人依赖于其他人。例如,该字段依赖于字段 。如果只标记,则它不会产生任何效果。可以通过 GUI 或命令检查依赖关系:DEBUG_INFO_BTF
DEBUG_INFO=y
DEBUG_INFO_BTF
make menuconfig
❯ cat lib/Kconfig.debug | grep "DEBUG_INFO_BTF" -A10
config DEBUG_INFO_BTF
bool "Generate BTF typeinfo"
depends on DEBUG_INFO
depends on !DEBUG_INFO_SPLIT && !DEBUG_INFO_REDUCED
depends on !GCC_PLUGIN_RANDSTRUCT || COMPILE_TEST
help
Generate deduplicated BTF type information from DWARF debug info.
Turning this on expects presence of pahole tool, which will convert
DWARF type info into equivalent deduplicated BTF type info.
最后一步是根据准备好的配置文件构建 Linux 内核。
make -j8
如果您仅选择了 LTS 版本,则一切都应按预期工作,因为新版本可用。对于没有支持的内核来说,它看起来更糟,例如5.8
linux-5.8.18.tar.xz 01-Nov-2020 11:52 109M
在构建旧内核时,您可能会遇到 较新编译器 的问题。对于旧代码来说,它可能太新了,并迫使您使用旧编译器构建内核。为了构建,我使用了带有板载内核的发行版。gcc
Linux 5.8
Ubuntu 18.04
5.4
生成的内核映像在路径./arch/x86/boot/bzImage
文件系统镜像
QEMU 需要文件系统镜像来了解如何启动系统。与 docker 环境不同,我们必须提供 init 系统来指示启动应该从哪里开始。您可以在 GitHub 上查看完整内容。几个重要步骤:Dockerfile
使用 Ubuntu 发行版 22.04 作为文件系统的基础
安装 init 系统 — systemd
install server 以便从主机进一步访问
SSH
准备 root 用户并允许自动登录
允许以 root 身份登录
SSH
启用网络接口
eth0
准备服务以运行应用程序和一些面向测试的应用程序
systemd
要基于您构建文件系统镜像,您必须从 Makefile 运行命令:Dockerfile
.ONESHELL:
prepare_e2e_filesystem:
# build filesystem image and store as tar archive
DOCKER_BUILDKIT=1 docker build --output "type=tar,dest=filesystem.tar" .
# convert tar to qcow2 image
sudo virt-make-fs --format=qcow2 --size=+100M filesystem.tar filesystem-large.qcow2
# reduce size of image
qemu-img convert filesystem-large.qcow2 -O qcow2 filesystem.qcow2
启动 QEMU 仿真
现在我们准备好开始对特定 Linux 内核进行 QEMU 仿真了。
.ONESHELL:
start_qemu:
# create differential image based on base image | new layer RW, base R only
sudo qemu-img create -f qcow2 -b filesystem.qcow2 -F qcow2 filesystem-diff.qcow2
sudo qemu-system-x86_64
# cpu model | host is recommended
-cpu host
# guest startup RAM size
-m 4G
# symmetric multiprocessing - cores count
-smp 4
# kernel image
-kernel ${PWD}/bzImage
# kernel command line
# send guest output to serial port ttyS0
# use /dev/sda to mount filesystem image
-append "console=ttyS0 root=/dev/sda rw"
# filesystem image and image format
-drive file="${PWD}/filesystem-diff.qcow2,format=qcow2"
# create Network Interface Card
-net nic
# configure host network
# forwart host port (10022) to guest port (22)
-net user,hostfwd=tcp::10022-:22,hostfwd=tcp::16676-:6676,hostfwd=tcp::10443-:443
# enable kvm full virtualization support
-enable-kvm
# where to store QEMU process PID
-pidfile qemu.pid
# disable graphical outpu
-nographic
运行测试
当 VM 启动时,我们可以准备环境来运行测试。我们可以通过 SSH 与 VM 连接,并将文件和命令发送到来宾操作系统。
.ONESHELL:
prepare_e2e: start_qemu
# wait for SSH port available
while ! nc -z 127.0.0.1 10022 ; do echo "waiting for ssh"; sleep 1; done
# send the k8spacket application to VM
sshpass -p root scp -o 'StrictHostKeyChecking no' -P 10022 ./k8spacket [email protected]:/root/k8spacket
sshpass -p root scp -o 'StrictHostKeyChecking no' -P 10022 ./fields.json [email protected]:/root/fields.json
# start systemd service responsible for the k8spacket application
sshpass -p root ssh -p 10022 [email protected] 'chmod 0655 /root/k8spacket && systemctl start k8spacket.service'
# wait for service to be active
while ! sshpass -p root ssh -p 10022 [email protected] 'systemctl is-active k8spacket.service' ; do echo "waiting for k8spacket service"; sleep 1; done
现在是运行测试的时候了
.ONESHELL:
e2e: prepare_e2e
# run test with environment variables
CLIENT_IP=10.0.2.2 HOST_IP=127.0.0.1 GUEST_IP=10.0.2.15 go test -v
RC=$$?
# print logs from k8spacket service
sshpass -p root ssh -p 10022 [email protected] 'journalctl -u k8spacket -n100'
# kill qemu process
sudo cat ./vm/filesystem/qemu.pid | sudo xargs kill
# return exit code from tests
exit $$RC
在 CI/CD 工作流中运行
QEMU 可以安装在大多数流行的 Linux 发行版上,并且很容易将其用作工作流程中的操作,例如 GitHub 操作。k8spacket 使用这种方法在合并到 master 之前测试 PR 中的更改。
它有效吗?
让我们测试一下负面情况。k8spacket 使用 map 类型将消息从内核发送到用户空间。此地图从 4.3 版本开始提供。让我们将其更改为 5.8 中的 available。K8sPacket 已在内核 5.4、5.8、5.15 及更高版本上进行了测试。切换后,我们可以假设一个测试失败 - 属于内核 5.4BPF_MAP_TYPE_PERF_EVENT_ARRAY
BPF_MAP_TYPE_RINGBUF
e2e-5.4
是唯一失败的测试 - 正如预期的那样。
总结
使用 QEMU 进行仿真是跨各种 Linux 内核测试 eBPF 程序的一种出色而强大的方法。它可以在投入生产之前为您提供保护,并对某些操作系统版本较旧的环境造成损害。
引用
https://mergeboard.com/blog/2-qemu-microvm-docker/ - 关于 QEMU 和基于 Dockerfile 构建的文件系统的第一步的优秀文章
https://vccolombo.github.io/cybersecurity/linux-kernel-qemu-setup/ - 关于编译内核和准备配置文件
https://github.com/grafana/beyla/tree/main/test/vm - 为 Grafana Beyla 制作的类似实现
https://www.qemu.org/docs/master/system/invocation.html - QEMU 系统仿真
https://www.kernel.org/ - 最新版本
其它相关课程
详细目录
QT开发底层原理与安全逆向视频教程
linux文件系统存储与文件过滤安全开发视频教程(2024最新)
linux高级usb安全开发与源码分析视频教程
linux程序设计与安全开发
windows恶意软件开发与对抗视频教程
windows网络安全防火墙与虚拟网卡(更新完成)
windows文件过滤(更新完成)
USB过滤(更新完成)
游戏安全(更新中)
ios逆向
windbg
还有很多免费教程(限学员)
更多详细内容添加作者微信
推荐站内搜索:最好用的开发软件、免费开源系统、渗透测试工具云盘下载、最新渗透测试资料、最新黑客工具下载……
还没有评论,来说两句吧...