mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1637 字
5 分钟
eBPF 安全:LSM 与进程监控
2026-04-07

传统的 Linux 安全方案面临一个根本矛盾:AppArmor/SELinux 策略强大但配置复杂,Seccomp 简单但只能过滤系统调用,Audit 可以审计但无法阻止。eBPF 提供了一种新的安全范式——LSM BPF 允许在内核安全检查点挂载 eBPF 程序,既能审计又能阻止,策略可编程且低开销。

与此同时,Tetragon 等基于 eBPF 的运行时安全工具,实现了零侵入的进程监控——无需修改应用代码,即可实时检测异常行为。

一、Linux 安全机制演进#

1.1 安全机制对比#

机制能力限制性能开销
DAC(自主访问控制)基于文件权限粗粒度极低
ACL细粒度文件权限仅文件系统
SELinux强制访问控制策略复杂
AppArmor路径级访问控制仅路径匹配
Seccomp系统调用过滤仅系统调用,无法审计
Audit审计日志无法阻止,仅审计中-高
LSM BPF可编程安全策略需要 5.7+ 内核

1.2 LSM BPF 的定位#

flowchart TB subgraph 传统安全["传统安全方案"] A1["SELinux/AppArmor<br/>强但复杂"] A2["Seccomp<br/>简单但受限"] A3["Audit<br/>审计但不阻止"] end subgraph eBPF安全["eBPF 安全方案"] B1["LSM BPF<br/>可编程 + 可阻止"] B2["进程监控<br/>零侵入 + 实时"] B3["运行时安全<br/>行为检测 + 自动响应"] end 传统安全 -->|"互补"| eBPF安全 style eBPF安全 fill:#c8e6c9,stroke:#2e7d32 style 传统安全 fill:#fff9c4,stroke:#f9a825

二、LSM BPF 详解#

2.1 LSM(Linux Security Module)框架#

LSM 是 Linux 内核的安全钩子框架,在关键操作点插入安全检查:

flowchart LR APP["用户态程序"] -->|"系统调用"| KERNEL["内核"] KERNEL -->|"LSM 钩子"| LSM["LSM 检查点"] LSM -->|"SELinux"| SEL["SELinux 策略"] LSM -->|"AppArmor"| AA["AppArmor 策略"] LSM -->|"BPF"| BPF["eBPF 策略<br/>LSM BPF"] SEL -->|"允许/拒绝"| DECISION["决策"] AA -->|"允许/拒绝"| DECISION BPF -->|"允许/拒绝"| DECISION style BPF fill:#c8e6c9,stroke:#2e7d32

2.2 LSM BPF 的工作原理#

LSM BPF 程序挂载在 LSM 钩子上,在安全检查时被调用:

  1. 内核执行安全敏感操作(如文件打开、进程创建)
  2. LSM 框架调用注册的钩子函数
  3. LSM BPF 程序被触发,检查操作是否允许
  4. 返回 0(允许)或 -EPERM(拒绝)

2.3 LSM 堆叠与共存#

Linux 5.1 引入了 LSM 堆叠(LSM Stacking),允许多个 LSM 模块同时生效。LSM BPF 作为”次要”LSM,可以与 SELinux/AppArmor 等”主要”LSM 共存——所有注册的 LSM 钩子依次执行,任一返回拒绝则操作被阻止:

flowchart LR OP["安全敏感操作"] --> SEL["SELinux<br/>主要 LSM"] SEL -->|"允许"| AA["AppArmor<br/>主要 LSM"] AA -->|"允许"| BPF["LSM BPF<br/>次要 LSM"] BPF -->|"允许"| ALLOW["操作执行"] SEL -->|"拒绝"| DENY["操作拒绝"] AA -->|"拒绝"| DENY BPF -->|"拒绝"| DENY style BPF fill:#c8e6c9,stroke:#2e7d32 style DENY fill:#ffcdd2,stroke:#c62828

启用 LSM BPF 需要在内核启动参数中添加 bpf 到 LSM 列表:

# 查看当前启用的 LSM
cat /sys/kernel/security/lsm
# lockdown,yama,integrity,apparmor
# 添加 bpf(需要重启)
# GRUB_CMDLINE_LINUX="lsm=lockdown,yama,integrity,apparmor,bpf"
Note

LSM BPF 的部署应遵循渐进式策略:先以审计模式运行(仅记录,不拒绝),确认策略无误后再切换为阻断模式。生产环境中错误的 LSM BPF 策略可能导致服务不可用——例如误阻 socket_connect 会让所有网络请求失败。

2.4 LSM 钩子列表#

钩子触发时机参数
inode_permission文件访问权限检查inode, mask
inode_create创建文件dir, dentry, mode
inode_unlink删除文件dir, dentry
inode_rename重命名文件old_dir, old_dentry, new_dir, new_dentry
file_open打开文件file
task_kill发送信号task, signal
task_setuid设置 UIDuid
bpfBPF 操作cmd, attr
socket_connectSocket 连接sock, address
socket_bindSocket 绑定sock, address
socket_listenSocket 监听sock
socket_acceptSocket 接受sock
ptrace_access_checkPtrace 访问检查task, mode
capget能力获取target, cap

2.5 LSM BPF 程序示例:文件访问控制#

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
// 受保护文件列表
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u64); // inode 号
__type(value, u32); // 允许的 UID
} protected_files SEC(".maps");
SEC("lsm/inode_permission")
int BPF_PROG(restrict_file_access, struct inode *inode, int mask)
{
u64 ino = BPF_CORE_READ(inode, i_ino);
u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
// 检查是否为受保护文件
u32 *allowed_uid = bpf_map_lookup_elem(&protected_files, &ino);
if (!allowed_uid)
return 0; // 非受保护文件,允许
// 检查当前用户是否有权限
if (uid != *allowed_uid) {
// 记录非法访问
bpf_trace_printk("Access denied: uid=%d ino=%lu\n", uid, ino);
return -EPERM; // 拒绝
}
return 0; // 允许
}
char LICENSE[] SEC("license") = "GPL";

2.6 LSM BPF 程序示例:网络连接控制#

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
// 允许连接的 IP 列表
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1024);
__type(key, u32); // 目标 IP
__type(value, u32); // 允许的 UID
} allowed_ips SEC(".maps");
SEC("lsm/socket_connect")
int BPF_PROG(restrict_connect, struct socket *sock, struct sockaddr *address)
{
struct sockaddr_in *addr = (struct sockaddr_in *)address;
u32 dst_ip = BPF_CORE_READ(addr, sin_addr.s_addr);
u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
u32 *allowed = bpf_map_lookup_elem(&allowed_ips, &dst_ip);
if (allowed && uid != *allowed)
return -EPERM;
return 0;
}
char LICENSE[] SEC("license") = "GPL";

2.7 Seccomp-BPF:系统调用过滤#

Seccomp-BPF 是 eBPF 在安全领域的早期应用——在系统调用入口处过滤,限制进程可调用的系统调用集合。Docker/Kubernetes 的安全上下文正是基于 Seccomp-BPF:

// Seccomp-BPF 程序:只允许基本系统调用
// 通过 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) 安装
SEC("socket")
int seccomp_filter(struct seccomp_data *ctx)
{
// ctx->nr 是系统调用号
// ctx->arch 是架构标识
// ctx->args[0..5] 是系统调用参数
switch (ctx->nr) {
case __NR_read:
case __NR_write:
case __NR_openat:
case __NR_close:
case __NR_fstat:
case __NR_mmap:
case __NR_munmap:
case __NR_brk:
case __NR_exit_group:
case __NR_clock_gettime:
return SECCOMP_RET_ALLOW; // 允许
case __NR_socket:
// 只允许 AF_INET 和 AF_INET6
if (ctx->args[0] == AF_INET || ctx->args[0] == AF_INET6)
return SECCOMP_RET_ALLOW;
return SECCOMP_RET_ERRNO | EAFNOSUPPORT;
default:
// 其他系统调用:记录并拒绝
return SECCOMP_RET_ERRNO | ENOSYS;
}
}

Seccomp-BPF 的局限在于只能过滤系统调用号和参数,无法跟踪调用序列或访问进程上下文。LSM BPF 弥补了这一缺口——它可以在安全检查点访问完整的内核对象(inode、socket、task),实现更细粒度的策略。

2.8 LSM BPF 审计模式#

LSM BPF 程序可以工作在两种模式:审计模式(仅记录,返回 0 允许)和阻断模式(返回 -EPERM 拒绝)。审计模式是安全策略上线的必经阶段:

// 审计模式:记录但不阻止
SEC("lsm/socket_connect")
int BPF_PROG(audit_connect, struct socket *sock, struct sockaddr *address)
{
u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
struct sockaddr_in *addr = (struct sockaddr_in *)address;
u32 dst_ip = BPF_CORE_READ(addr, sin_addr.s_addr);
u32 *blocked = bpf_map_lookup_elem(&blocked_ips, &dst_ip);
if (blocked && uid != *blocked) {
// 审计模式:仅记录事件到 Ring Buffer
struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (e) {
e->type = EVENT_BLOCKED_CONNECT;
e->uid = uid;
e->dst_ip = dst_ip;
bpf_ringbuf_submit(e, 0);
}
// 审计模式:仍然允许
return 0;
// 阻断模式:取消上面 return 0,改为:
// return -EPERM;
}
return 0;
}
Note

从审计模式切换到阻断模式,只需修改 eBPF 程序的返回值——无需修改策略逻辑或重新部署。建议审计模式至少运行 1-2 周,收集足够的事件样本后再切换。

三、Tetragon:eBPF 运行时安全#

3.1 Tetragon 架构#

Tetragon 是 Isovalent(Cilium 公司)开源的 eBPF 运行时安全监控工具:

flowchart TB subgraph 内核空间 TP["Tracing Policy<br/>eBPF 程序"] --> HOOK["kprobe/tracepoint<br/>LSM 钩子"] HOOK --> EVENT["事件数据"] end subgraph 用户空间 TETRA["Tetragon Daemon"] --> FILTER["事件过滤<br/>策略匹配"] FILTER --> ACTION["响应动作<br/>告警/阻止/记录"] ACTION --> EXPORT["导出<br/>JSON/CLI/gRPC"] end EVENT --> TETRA style TP fill:#c8e6c9,stroke:#2e7d32 style TETRA fill:#bbdefb,stroke:#1565c0

3.2 Tetragon 的核心能力#

能力说明
进程执行监控追踪 execve/fork/exit
文件访问监控追踪 open/read/write/close
网络连接监控追踪 connect/accept/bind
系统调用过滤基于 Seccomp-BPF
内核模块监控追踪模块加载/卸载
特权提升检测追踪 capabilities 变化
容器安全关联 K8s 元数据
实时响应通过 LSM BPF 阻止恶意行为

3.3 Tetragon TracingPolicy#

# Tetragon TracingPolicy 示例:监控所有进程执行
apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: monitor-process-exec
spec:
kprobes:
- call: "sys_execve"
syscall: true
args:
- index: 0
type: "string"
selectors:
- matchNames:
- namespace: "default"
return: true
returnArg:
index: 0
type: "int"

3.4 Tetragon 部署#

# 使用 Helm 部署 Tetragon
helm repo add cilium https://helm.cilium.io
helm install tetragon cilium/tetragon -n kube-system
# 查看 Tetragon 日志
kubectl logs -n kube-system -l app.kubernetes.io/name=tetragon
# 使用 tetragon CLI 查看事件
kubectl exec -n kube-system tetragon-xxx -- tetra getevents

3.5 Tetragon 实战:检测特权容器#

apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata:
name: detect-privileged-exec
spec:
kprobes:
- call: "cap_capable"
args:
- index: 1
type: "int"
- index: 2
type: "int"
- index: 3
type: "int"
selectors:
- matchArgs:
- index: 2
operator: "Equal"
values:
- "21" # CAP_SYS_ADMIN

四、eBPF 进程监控#

4.1 进程生命周期追踪#

#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
struct event {
u32 pid;
u32 ppid;
char comm[16];
char filename[256];
u8 type; // 0=exec, 1=fork, 2=exit
};
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} events SEC(".maps");
// 追踪进程执行
SEC("tracepoint/sched/sched_process_exec")
int trace_exec(struct trace_event_raw_sched_process_template *ctx)
{
struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0;
e->type = 0;
e->pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
struct task_struct *task = (struct task_struct *)bpf_get_current_task();
e->ppid = BPF_CORE_READ(task, real_parent, pid);
bpf_ringbuf_submit(e, 0);
return 0;
}
// 追踪进程退出
SEC("tracepoint/sched/sched_process_exit")
int trace_exit(struct trace_event_raw_sched_process_template *ctx)
{
struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0;
e->type = 2;
e->pid = bpf_get_current_pid_tgid() >> 32;
bpf_get_current_comm(&e->comm, sizeof(e->comm));
bpf_ringbuf_submit(e, 0);
return 0;
}
char LICENSE[] SEC("license") = "GPL";

4.2 异常行为检测#

检测场景eBPF Hook检测逻辑
反弹 Shelltracepoint/sys_enter_execvebash/nc 执行后发起网络连接
特权提升kprobe/cap_capableCAP_SYS_ADMIN 获取
文件篡改tracepoint/sys_enter_openat敏感文件以写模式打开
异常网络tracepoint/sys_enter_connect未知目标 IP 连接
内核模块加载tracepoint/module_load非预期模块加载
容器逃逸LSM/bpf容器内使用 bpf() 系统调用

五、eBPF 安全最佳实践#

5.1 纵深防御#

flowchart TB subgraph 防御层["纵深防御"] L1["网络层<br/>XDP/TC 防火墙"] L2["系统调用层<br/>Seccomp-BPF"] L3["LSM 层<br/>LSM BPF 策略"] L4["应用层<br/>进程行为监控"] end L1 --> L2 --> L3 --> L4 style 防御层 fill:#e8eaf6,stroke:#283593

5.2 安全原则#

Warning

eBPF 安全不是银弹。它不能替代 SELinux/AppArmor,而是作为补充。正确的做法是纵深防御——多层安全机制协同工作,eBPF 提供实时的行为监控和快速响应能力。

  1. 最小权限:eBPF 程序本身也需要 CAP_BPF 权限,限制谁能加载 eBPF 程序
  2. 策略即代码:安全策略通过 TracingPolicy/YAML 管理,版本控制
  3. 渐进式部署:先审计模式(仅记录),再阻断模式(拒绝)
  4. 关联上下文:将 eBPF 事件与 K8s 元数据关联,精确定位问题 Pod

六、动手实践#

6.1 使用 bpftrace 监控进程行为#

# 追踪所有进程执行
sudo bpftrace -e 'tracepoint:sched:sched_process_exec {
printf("EXEC: pid=%d comm=%s\n", pid, comm);
}'
# 追踪特权操作
sudo bpftrace -e 'kprobe:cap_capable {
if (arg2 == 21) // CAP_SYS_ADMIN
printf("CAP_SYS_ADMIN: pid=%d comm=%s\n", pid, comm);
}'
# 追踪网络连接
sudo bpftrace -e 'tracepoint:syscalls:sys_enter_connect {
printf("CONNECT: pid=%d comm=%s\n", pid, comm);
}'

6.2 编写 LSM BPF 程序#

# 检查内核是否支持 LSM BPF
cat /sys/kernel/security/lsm
# 输出应包含 "bpf"
# 如果不包含,需要添加内核参数
# GRUB_CMDLINE_LINUX="lsm=lockdown,yama,integrity,apparmor,bpf"

6.3 部署 Tetragon#

# 快速部署
kubectl apply -f https://raw.githubusercontent.com/cilium/tetragon/main/install/kubernetes/tetragon.yaml
# 查看实时事件
kubectl exec -n kube-system ds/tetragon -- tetra getevents -o compact

七、本章小结#

上一章理解了eBPF 网络全景。 本章详解了 eBPF 在安全领域的应用:

主题核心要点关键词
LSM BPF在内核安全检查点挂载 eBPF 程序,实现可编程的安全策略LSM BPF
Tetragon基于 eBPF 的运行时安全监控,零侵入、实时检测Tetragon
进程监控追踪进程生命周期、检测异常行为进程监控
纵深防御eBPF 安全与传统安全机制互补,而非替代纵深防御

支持与分享

如果这篇文章对你有帮助,欢迎支持作者或分享给更多人

eBPF 安全:LSM 与进程监控
https://blog.souloss.com/posts/ebpf/ebpf-security/
作者
Souloss
发布于
2026-04-07
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

相关文章 智能推荐
1
eBPF 虚拟机:指令集与寄存器
eBPF eBPF 虚拟机是 eBPF 程序的执行引擎——它定义了指令集、寄存器模型和内存访问方式。逐层拆解 eBPF 指令集的每一条指令,解析 10 个寄存器的用途,剖析 ALU/JMP/内存操作,并揭示 JIT 编译如何将字节码转化为接近原生的执行速度。
2
eBPF 验证器:如何保证安全
eBPF eBPF 验证器是 eBPF 安全的基石——它在程序加载时进行静态分析,确保 eBPF 程序不会崩溃内核、不会越界访问内存、不会无限循环。从零讲透验证器的 DAG 验证算法、路径探索机制、安全检查规则,并解析常见的验证失败原因与修复方法。
3
综合实战:构建 eBPF 网络安全工具
eBPF 综合实战——从零构建 eBPF 网络安全工具——XDP 防 DDoS + TC 流量控制 + LSM 进程监控,运用前 17 章知识解决真实安全问题。
4
系列导读
eBPF 本系列从 eBPF 的底层原理出发,系统讲解 eBPF 虚拟机、验证器、Map 数据结构、Hook 机制、CO-RE 可移植性,再到 XDP/TC 网络处理、LSM 安全、Cilium 实践、Wasm 融合、Kubernetes 集成与生产部署,带你从「听说过 eBPF」进阶到「能用 eBPF 解决真实问题」。
5
eBPF 与 WebAssembly
eBPF eBPF 提供内核可编程能力,WebAssembly 提供跨平台可移植性——两者的融合会带来什么?本章详解 Wasm-eBPF 项目、用户态 eBPF 运行时、eBPF 程序的 Wasm 封装,以及 eBPF + Wasm 在边缘计算、插件系统、跨平台可观测性中的应用前景。