为什么 eBPF 让传统安全工具"失业"?
过去十年,Linux 安全监控领域经历了一场静默的革命。传统方案——基于 ptrace 的审计、内核模块 (LSM)、系统调用钩子——要么性能损耗巨大,要么稳定性堪忧。eBPF 的出现彻底改变了游戏规则:它在内核内运行沙箱化的字节码,无需修改内核源码、无需加载内核模块,就能以极低的开销观测系统的每一个角落。
本文将从工程实践角度,解构 eBPF 在安全监控领域的核心架构,并给出可落地的代码方案。
eBPF 安全工具的核心优势
与传统方案对比,eBPF 安全工具有三个不可忽视的优势:
| 维度 | 传统 auditing (auditd) | 内核模块 (LKM) | eBPF |
|---|---|---|---|
| 性能开销 | 高(每个 syscall 产生事件) | 中等 | 极低(JIT 编译、无上下文切换) |
| 稳定性 | 内核 ABI 稳定 | 版本绑定、易 panic | Verifier 保证安全、跨版本兼容 |
| 部署灵活性 | 需配置规则文件 | 需编译、insmod | 动态加载、热插拔 |
| 可见性 | 仅 syscall 层 | 全空间 | 全栈(syscall、XDP、kprobe、tracepoint) |
核心架构解析
1. 程序类型与安全钩子
eBPF 针对不同场景提供了丰富的程序类型。安全监控场景最核心的有:
// kprobe/kretprobe:动态挂钩任意内核函数
// 经典场景:挂钩 execve、do_exit 监控系统调用
SEC("kprobe/do_exit")
int trace_do_exit(struct pt_regs *ctx) {
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
u32 pid = BPF_CORE_READ(task, tgid);
struct event e = {};
e.timestamp = bpf_ktime_get_ns();
e.pid = pid;
e.exit_code = PT_REGS_PARM1(ctx);
bpf_perf_event_output(ctx,

发表评论 取消回复