
核心要点(TL;DR)
- eBPF 可在内核态无侵入监控进程与文件行为,实现低开销 HIDS。
- 通过 tracepoint 和 kprobe 挂载 eBPF 程序,捕获 execve 和文件操作事件。
- 结合用户态守护进程分析事件流,可实时告警异常进程与敏感文件访问。
- 部署前需确认内核版本≥4.9 并开启 BPF 相关配置。
为什么需要 eBPF 主机入侵检测?
传统 HIDS 依赖用户态轮询(如 ps、lsof)或审计日志(auditd),存在延迟高、资源消耗大、易被绕过等痛点。eBPF 允许在内核态安全地执行沙箱程序,实时捕获进程与文件系统事件,实现低开销、高精度的入侵检测。本文将手把手带你用 eBPF 构建一个轻量级监控原型,涵盖进程执行与敏感文件访问的捕获与分析。
环境准备与内核要求
首先确认系统支持 eBPF:
uname -r # 建议 4.9 以上,推荐 5.4+
grep CONFIG_BPF /boot/config-$(uname -r) # 应输出 CONFIG_BPF=y 和 CONFIG_BPF_SYSCALL=y安装必要工具链(以 Ubuntu 为例):
sudo apt install -y clang llvm libelf-dev libbpf-dev linux-tools-common linux-tools-$(uname -r) bpftool验证 bpftool 可用:
sudo bpftool feature probe若输出包含 “eBPF syscall” 和 “BPF maps” 等支持信息,则环境就绪。
捕获进程执行事件
进程创建是入侵检测的关键点。我们通过 tracepoint 捕获 execve 系统调用,记录进程路径与参数。编写 eBPF 程序(C 语言):
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
struct event {
u32 pid;
char comm[16];
char filename[256];
};
struct bpf_map_def SEC("maps") events SEC(".maps") = {
.type = BPF_MAP_TYPE_RINGBUF,
.max_entries = 256 * 1024,
};
SEC("tracepoint/syscalls/sys_enter_execve")
int handle_execve(void *ctx) {
struct event *e;
e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0;
e->pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
bpf_probe_read_user_str(&e->filename, sizeof(e->filename), (void *)ctx + 8); // 参数偏移需根据架构调整
bpf_ringbuf_submit(e, 0);
return 0;
}
char LICENSE[] SEC("license") = "GPL";用户态程序使用 libbpf 加载并读取 ring buffer,输出事件。编译命令:
clang -O2 -target bpf -c execve.bpf.c -o execve.bpf.o加载后运行用户态程序,即可实时看到进程执行记录。
监控敏感文件访问
文件监控聚焦于 /etc、/bin、/usr/bin 等目录的写入与打开操作。通过 kprobe 挂载到 vfs_open 和 vfs_write:
SEC("kprobe/vfs_open")
int handle_vfs_open(struct pt_regs *ctx, struct path *path) {
struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0;
e->pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
// 读取 path->dentry->d_name.name 到 filename
bpf_probe_read_kernel_str(&e->filename, sizeof(e->filename), path->dentry->d_name.name);
bpf_ringbuf_submit(e, 0);
return 0;
}用户态程序过滤文件路径前缀(如 /etc/),仅对敏感操作告警。注意:vfs_open 触发频繁,需在 eBPF 程序中做初步过滤以减少事件量。
部署与检查清单
将 eBPF 程序编译为字节码,通过 systemd 服务常驻运行。部署前检查:
- 内核版本 ≥ 4.9,且启用 BPF 相关配置;
- 已安装 clang、llvm、libbpf 等工具;
- 用户态程序具有 CAP_BPF 或 root 权限;
- ring buffer 大小合理(建议 256KB~1MB);
- 敏感文件路径列表已配置;
- 日志输出到 syslog 或文件,并设置轮转。
运行后,使用 bpftool 查看已加载程序:
sudo bpftool prog list检查事件流是否正常:
sudo ./hids-monitor -f /etc/若输出进程与文件事件,则监控生效。
行动建议
eBPF 主机入侵检测具备低开销、实时性强的优势,适合作为传统 HIDS 的补充或替代。建议从监控进程执行和敏感文件写入开始,逐步扩展网络连接、权限提升等事件。生产环境可结合 AegisX 的 eBPF 安全能力,实现开箱即用的入侵检测与响应,减少自研维护成本。立即动手编写你的第一个 eBPF 监控程序,体验内核态安全的威力。
常见问题(FAQ)
eBPF 主机入侵检测需要什么内核版本?
建议使用 Linux 内核 4.9 及以上版本,并确保编译时开启 CONFIG_BPF、CONFIG_BPF_SYSCALL 等选项。生产环境推荐 5.x 以上内核以获得更完善的 eBPF 特性支持,如 BTF 和 CO-RE,便于程序移植。
eBPF 监控会影响系统性能吗?
eBPF 程序在内核态运行,经过 JIT 编译后性能开销极低,通常对系统吞吐影响小于 1%。但需注意避免在 eBPF 程序中执行复杂逻辑或频繁向用户态发送大量事件,否则可能增加 CPU 负载。合理设置采样和过滤规则可进一步降低开销。
如何捕获进程执行事件?
可通过挂载 eBPF 程序到 tracepoint:syscalls:sys_enter_execve 或 kprobe:__x64_sys_execve 来捕获进程执行事件。在 eBPF 程序中读取寄存器或参数字段获取可执行文件路径和参数,然后通过 perf event 或 ring buffer 发送到用户态分析。
eBPF 能监控文件打开和写入吗?
可以。通过 kprobe 挂载到 vfs_open、vfs_write 等内核函数,或使用 tracepoint:syscalls:sys_enter_openat 和 sys_enter_write,能够捕获文件路径、操作类型和进程信息。结合文件路径过滤,可重点监控敏感目录如 /etc、/bin 等。
如何将 eBPF 事件输出到用户态?
常用方式包括 perf event array 和 BPF ring buffer。perf event array 兼容性好,适合高吞吐场景;ring buffer 更高效且支持多消费者。用户态程序通过 libbpf 或 BCC 框架读取事件,进行聚合、告警和存储。