引言
在容器化技术的安全体系中,seccomp-BPF(Secure Computing with Berkeley Packet Filter)是最关键的防线之一。无论是 Docker、Kubernetes、Podman 还是 gVisor,底层都依赖 seccomp-BPF 限制容器内进程可执行的系统调用集合,从而构建「最小权限(Least Privilege)」的安全沙箱。然而,大多数工程师对 seccomp 的理解停留在 Docker 的默认配置文件层面——它默认拦截约 44 个高危系统调用。本文将深入剖析 seccomp-BPF 的内核实现机制、BPF 过滤器的编译与执行流程、策略编写最佳实践,以及如何为不同容器场景构建定制化的安全沙箱。
1. Secure Computing Mode 的演进
1.1 seccomp 的诞生:模式 1
Linux 2.6.12(2005 年)首次引入了 seccomp。最初的 seccomp 极为严格:
// 原始 seccomp(模式 1):允许仅 4 个系统调用
// 模式:SCMP_ACT_TRAP → 触发 SIGSYS
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
// 允许的系统调用:
// - read() - 读文件
// - write() - 写文件
// - _exit() - 退出进程
// - sigreturn() - 从信号返回
// 任何其他系统调用 → 触发 SIGKILL(强制杀死进程)
这个模式太严格,几乎没有实用价值(任何需要 mmap、brk 的程序都无法运行)。
1.2 seccomp-BPF:模式 2 的革命
Linux 3.5(2012 年)引入 seccomp-BPF,允许使用 BPF 程序自定义过滤规则:
// seccomp-BPF 基本用法
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>
struct sock_filter filter[] = {
// 1. 加载系统调用号到累加器
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
// 2. 如果是 exit_group,允许
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_exit_group, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
// 3. 如果是 write,允许(fd==1/2 标准输出/错误)
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
// 4. 其他系统调用 → 返回 EPERM
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ERRNO | (EPERM & SECCOMP_RET_DATA)),
};
struct sock_fprog prog = {
.len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),
.filter = filter,
};
prctl(PR_SET_NO_NEWPRIVS, 1, 0, 0, 0);
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
2. seccomp-BPF 的内核执行流程
2.1 seccomp_data 结构
当系统调用发生时,内核构造一个 seccomp_data 结构供 BPF 过滤器检查:
struct seccomp_data {
int nr; // 系统调用号(架构相关)
__u32 arch; // 架构标识(AUDITEBUST_X86_64 等)
__u64 instruction_pointer; // 调用时的 RIP
__u64 args[6]; // 系统调用参数(6 个)
};
// BPF 过滤器可以检查:
// - 系统调用号 (nr)
// - 架构 (arch) → 防止攻击者利用 32-bit 系统调用绕过
// - 每个参数 (args[0..5]) → 基于参数值过滤
// 但不能检查:
// - 指针指向的内容(内核不会自动解引)
// - 用户空间数据结构
2.2 BPF 过滤器的编译与加载
// 内核 seccomp 检查流程(简化)
// arch/x86/entry/common.c → seccomp_run_filters()
static int seccomp_run_filters(struct seccomp_data *sd) {
struct sock_filter *filter;
unsigned short len;
for (each filter in current->seccomp.filter) {
// BPF 虚拟机执行过滤程序
// 使用 seccomp BPF 虚拟机(不同于网络 BPF)
unsigned int result = bpf_prog_run(filter, sd);
// 高 16 位 = action,低 16 位 = data
u32 action = result & SECCOMP_RET_ACTION_FULL;
u32 data = result & SECCOMP_RET_DATA;
switch (action) {
case SECCOMP_RET_ALLOW:
return 0; // 允许系统调用
case SECCOMP_RET_TRAP:
force_sig(SIGSYS, current); // 发送 SIGSYS
return -ENOSYS;
case SECCOMP_RET_ERRNO:
return -data; // 返回指定 errno
case SECCOMP_RET_TRACE:
// 通知 ptrace tracer 介入
ptrace_event(PTRACE_SECCOMP, data);
return -ENOSYS;
case SECCOMP_RET_LOG:
// 记录审计日志但允许
audit_seccomp(current, 0, data);
return 0;
case SECCOMP_RET_KILL_PROCESS:
force_sig(SIGKILL, current); // 杀死进程
return -ENOSYS;
case SECCOMP_RET_KILL_THREAD:
do_exit(SIGKILL); // 杀死当前线程
default:
return -EINVAL;
}
}
return SECCOMP_RET_TRAP; // 默认行为(除非配置)
}
2.3 SECCOMP_RET_ACTION 完整取值表
| 返回值 | 动作 | 适用场景 |
|---|---|---|
| SECCOMP_RET_ALLOW | 允许执行 | 白名单系统调用 |
| SECCOMP_RET_TRAP | 触发 SIGSYS 信号 | 调试/可恢复拦截 |
| SECCOMP_RET_ERRNO(errno) | 以 errno 失败返回 | 静默拦截 |
| SECCOMP_RET_TRACE | 通知 ptrace tracer | 动态 Allow |
| SECCOMP_RET_LOG | 允许但记录审计日志 | 审计模式 |
| SECCOMP_RET_KILL_THREAD | 立即杀死当前线程 | 严格模式 |
| SECCOMP_RET_KILL_PROCESS | 杀死整个进程 | Linux 4.14+ |
3. libseccomp:生产级策略编写
3.1 基本 API 用法
libseccomp 封装了 BPF 生成过程,提供安全的 API:
#include <seccomp.h>
#include <errno>
int main() {
// 1. 创建 seccomp 上下文
// SCMP_ACT_ERRNO(EPERM) → 默认动作:返回 EPERM
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_ERRNO(EPERM));
if (!ctx) return 1;
// 2. 匹配架构(关键:防止 32-bit 攻击)
// 只允许当前架构,拒绝所有其他架构的系统调用
uint32_t archs[] = {
SCMP_ARCH_X86_64,
SCMP_ARCH_X86,
SCMP_ARCH_X32,
};
for (int i = 0; i < sizeof(archs)/sizeof(archs[0]); i++) {
if (seccomp_arch_native() != archs[i]) {
seccomp_arch_add(ctx, archs[i]);
}
}
// 3. 添加允许的系统调用
int allowed_calls[] = {
SCMP_SYS(read), SCMP_SYS(write),
SCMP_SYS(close), SCMP_SYS(fstat),
SCMP_SYS(mmap), SCMP_SYS(mprotect),
SCMP_SYS(munmap), SCMP_SYS(brk),
SCMP_SYS(rt_sigreturn), SCMP_SYS(rt_sigprocmask),
SCMP_SYS(rt_sigaction), SCMP_SYS(ioctl),
SCMP_SYS(access), SCMP_SYS(pipe),
SCMP_SYS(sched_yield), SCMP_SYS(dup),
SCMP_SYS(dup2), SCMP_SYS(nanosleep),
SCMP_SYS(getpid), SCMP_SYS(getppid),
SCMP_SYS(exit_group), SCMP_SYS(futex),
SCMP_SYS(set_robust_list), SCMP_SYS(clock_gettime),
SCMP_SYS(prlimit64), SCMP_SYS(getrandom),
SCMP_SYS(sigaltstack),
};
for (int i = 0; i < sizeof(allowed_calls)/sizeof(allowed_calls[0]); i++) {
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, allowed_calls[i], 0);
}
// 4. 特殊规则:限制 ioctl 的参数
// 只允许 TIOCGWINSZ(获取终端大小)
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(ioctl), 1,
SCMP_A1(SCMP_CMP_EQ, TIOCGWINSZ));
// 5. 限制 clone/clone3 参数:禁止创建新命名空间
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(clone), 1,
SCMP_A0(SCMP_CMP_MASKED_EQ, CLONE_NEWUSER, 0));
// 6. 加载并激活
seccomp_load(ctx);
seccomp_release(ctx); // 释放内核 BPF 程序
// 7. 此后任何未列出的系统调用 → 返回 EPERM
// 尝试 open() → -EPERM
return 0;
}
3.2 高级参数匹配
// 参数匹配规则详解
// seccomp_rule_add(ctx, action, syscall_nr, arg_count, ...)
// 1. 精确匹配
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(openat), 2,
SCMP_A0(SCMP_CMP_EQ, AT_FDCWD), // 第1参数 == AT_FDCWD
SCMP_A1(SCMP_CMP_MASKED_EQ, O_WRONLY, 0) // 第2参数 & O_WRONLY == 0(只读打开)
);
// 2. 掩码匹配(常用于 flags 参数)
// 检查 mmap 是否包含 PROT_EXEC(可执行内存)
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(mmap), 1,
SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC) // prot & PROT_EXEC != 0 → 拒绝
);
// 3. 不等于匹配
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(prctl), 1,
SCMP_A0(SCMP_CMP_NE, PR_SET_SECCOMP) // 不允许再设置 seccomp
);
// 4. 多架构支持
// X32 系统调用号与 X86_64 不同,需特殊处理
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(time), 0); // 在所有架构上允许
4. Docker 默认 seccomp 配置文件解析
4.1 默认策略结构
// 来自 Docker 默认 seccomp 配置文件(简化版)
{
"defaultAction": "SCMP_ACT_ERRNO", // 默认返回 EPERM
"defaultErrnoRet": 1,
"archMap": [
{ "architecture": "SCMP_ARCH_X86_64",
"subArches": ["SCMP_ARCH_X86", "SCMP_ARCH_X32"] }
],
"syscalls": [
{
"names": [
"accept", "accept4", "access", "adjtimex",
"alarm", "bind", "brk", "capget", "capset",
"chdir", "chmod", "chown", "chroot",
"clock_getres", "clock_gettime", "clock_nanosleep",
"clone", "close", "connect", "copy_file_range",
"dup", "dup2", "dup3", "epoll_create1",
// ... 约 300+ 个允许的系统调用
],
"action": "SCMP_ACT_ALLOW",
"args": [],
"comment": "允许大多数常见系统调用",
"includes": {
"caps": ["CAP_SYS_ADMIN"] // 有 CAP_SYS_ADMIN 时包含
}
},
{
"names": ["clone"],
"action": "SCMP_ACT_ALLOW",
"args": [
{
"index": 0,
"value": 2080505856, // CLONE_THREAD | CLONE_SIGHAND | ...
"op": "SCMP_CMP_MASKED_EQ",
"valueTwo": 2080505856 // 掩码匹配
}
]
},
{
"names": ["bpf", "fanotify_init", "lookup_dcookie",
"mount", "name_to_handle_at", "perf_event_open",
"quotactl", "setdomainname", "sethostname",
"setns", "syslog", "umount", "umount2",
"unshare"],
"action": "SCMP_ACT_ERRNO",
"comment": "拒绝高危系统调用(容器逃逸向量)"
}
]
}
4.2 Docker 默认拒绝的关键系统调用
| 系统调用 | 风险 | 攻击向量 |
|---|---|---|
| bpf() | 加载 eBPF 程序 | 内核提权、容器逃逸 |
| ptrace() | 调试追踪其他进程 | 注入攻击 |
| mount() | 挂载文件系统 | 挂载 host /proc、/dev 获取 host 信息 |
| unshare() | 创建新命名空间 | 绕过容器隔离 |
| setns() | 加入已有命名空间 | 加入 init_pid_ns 逃逸 |
| perf_event_open() | 性能监控 | 侧信道攻击(Spectre/Meltdown 变种) |
| kexec_load() | 热替换内核 | 加载恶意内核 |
| reboot() | 重启系统 | DoS |
| swapon()/swapoff() | 管理交换空间 | 获取 swap 数据 |
| open_by_handle_at() | 通过文件句柄打开 | 绕过路径权限检查 |
5. Kubernetes 中的 seccomp 配置
5.1 Pod 级别配置
# Pod 使用自定义 seccomp 配置文件
apiVersion: v1
kind: Pod
metadata:
name: sandboxed-app
annotations:
# 指向 Node 上的 seccomp 配置文件
seccomp.security.alpha.kubernetes.io/pod: "runtime/default"
# 或自定义路径
seccomp.security.alpha/kubernetes.io/pod: "localhost/my-profiles/strict.json"
spec:
containers:
- name: app
image: myapp:latest
securityContext:
seccompProfile:
type: Localhost # 使用自定义 profile
localhostProfile: "profiles/restricted.json"
# 或: type: RuntimeDefault → 使用容器运行时默认
# 或: type: Unconfined → 禁用 seccomp(不推荐)
# 全局 Seccomp 配置目录
# Node 路径: /var/lib/kubelet/seccomp/PROFILE_NAME
5.2 使用 Security Admission Controller 强制 seccomp
# Kubernetes 1.25+ Pod Security Standards
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
# 强制 baseline 标准(包含 seccomp 要求)
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: latest
---
# baseline 标准要求:
# - 必须使用 seccomp(不能为 Unconfined)
# - RuntimeDefault 或 localhost profile 均可
6. 高级技术:Seccomp Notify 动态策略
6.1 Seccomp Notify 工作原理(Linux 5.0+)
Seccomp Notify 允许用户空间程序(如容器运行时的 supervisor)在进程触发被拦截的系统调用时,由 supervisor 代为执行该调用,实现动态策略:
// Seccomp Notify 流程
//
// 1. 进程 P 的 seccomp 规则设置 SECCOMP_RET_USER_NOTIF
// 2. 当 P 调用被拦截的系统调用 → 内核生成通知(not 立即拒绝)
// 3. Supervisor 通过 SECCOMP_IOCTL_NOTIF_RECV 接收
// 4. Supervisor 检查请求,决定是否允许/修改/拒绝
// 5. Supervisor 可通过 SECCOMP_IOCTL_NOTIF_SEND 响应
// 或代为执行系统调用(SECCOMP_IOCTL_NOTIF_ID_VALID)
// 步骤1:创建 SECCOMP_RET_USER_NOTIF 规则
struct sock_filter filter[] = {
BPF_STMT(BPF_LD | BPF_W | BPF_ABS,
offsetof(struct seccomp_data, nr)),
// openat 系统调用 → 发送用户通知
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_openat, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_USER_NOTIF),
// 其他系统调用 → 允许
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_fprog prog = { .len = 26, .filter = filter };
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
// 步骤2:Supervisor 侧处理通知
struct seccomp_notif *req;
seccomp_notify_fd = seccomp(SECCOMP_GET_NOTIF_SIZES, 0, &sizes);
while (1) {
seccomp_notify_recv(fd, req); // 阻塞等待通知
// 检查是哪个系统调用
if (req->data.nr == __NR_openat) {
// 检查进程试图打开的路径
char path[256];
process_vm_readv(req->pid, &(struct iovec){path, 256},
&(struct iovec){req->data.args[1], 256}, 1, 0);
if (is_safe_path(path)) {
// 代为执行 openat,返回 fd
int fd = openat(req->data.args[0], path, req->data.args[2]);
seccomp_notify_send(fd, resp_with_fd);
} else {
// 拒绝 → EPERM
seccomp_notify_send(fd, resp_with_errno(EPERM));
}
}
}
6.2 基于 Seccomp Notify 的安全沙箱实现
gVisor 和 Sysbox 等容器运行时使用 Seccomp Notify 实现完整的系统调用虚拟化:
// gViser 的 gofer 进程(基于 seccomp notify 的文件访问代理)
//
// 容器内进程调用 open() → seccomp 拦截 → Supervisor 接收
// → Supervisor 检查路径
// → 在 host 代为 open()
// → 返回 fd 给容器进程
//
// 关键特性:
// 1. 路径白名单:只能访问授权目录
// 2. 访问审计:记录所有文件访问
// 3. 动态注入策略:无需重启容器即可更新
//
// 性能优化:
// - 使用共享内存传递路径数据(避免 /proc/pid/mem)
// - 批处理系统调用(减少通知轮次)
// - 缓存常用路径的授权结果
// 开销对比(Phoronix 测试, 2023):
// ┌──────────────────────┬────────────┬────────────┐
// │ 场景 │ native │ seccomp notify│
// ├──────────────────────┼────────────┼────────────┤
// │ 文件 I/O (读 4KB) │ 12.1 µs │ 18.7 µs (+55%)│
// │ getpid() │ 0.12 µs │ 0.15 µs (+25%)│
// │ mmap (4MB) │ 8.3 µs │ 12.1 µs (+46%)│
// │ socket() 创建 │ 2.1 µs │ 9.8 µs (+367%)│
// └──────────────────────┴────────────┴────────────┘
7. 安全审计与策略调优实战
7.1 使用 strace 发现所需系统调用
// 步骤 1:收集目标容器的系统调用日志
$ strace -p $(pidof myapp) -f -o /tmp/app_trace.log &
// 步骤 2:运行应用的典型工作负载
// (创建测试数据、处理请求、清理等)
// 步骤 3:分析系统调用分布
$ awk '{print $2}' /tmp/app_trace.log | grep -oP '^[a-z_]+' | sort | uniq -c | sort -rn
52342 read
41287 write
18453 epoll_wait
12487 futex
8921 clock_gettime
6743 brk
4521 mmap
3287 mprotect
2183 close
1891 openat # ← 需要白名单
1564 newfstatat
1203 rt_sigaction
987 ioctl
623 access
412 fcntl
32 getdents64
15 munmap
9 sigaltstack
8 rt_sigprocmask
7 arch_prctl
5 set_robust_list
5 set_tid_address
3 rseq
...
// 步骤 4:识别不再使用的调用 → 加入黑名单精简策略
7.2 使用 BPF CO-RE 进行 Seccomp 策略审计
// 使用 eBPF 追踪 seccomp 决策(审计模式)
// seccomp_monitor.bpf.c
SEC("tp/raw_syscalls/sys_exit")
int trace_seccomp_exit(struct trace_event_raw_sys_exit *ctx) {
u32 pid = bpf_get_current_pid_tgid() >> 32;
s32 ret = ctx->ret;
// 监控系统调用返回 EPERM (errno=1)
if (ret == -EPERM) {
struct event ev = {};
ev.pid = pid;
ev.ts = bpf_ktime_get_ns();
ev.ret = ret;
bpf_get_current_comm(&ev.comm, sizeof(ev.comm));
// 记录被 seccomp 拦截的进程
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &ev, sizeof(ev));
}
return 0;
}
// 配合 userspace 工具可以检测新部署应用是否
// 被当前 seccomp 策略影响,从而迭代优化策略
8. 常见陷阱与开发者指南
8.1 32-bit 架构绕过(x32 ABI)
// 错误:只拦截 64-bit 系统调用号
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(openat), 0);
// 攻击者可能使用 32-bit openat:
// 64-bit openat = 257 → 被拦截
// 32-bit openat = 295 → 可能绕过(如果不在黑名单中)
// 正确:显式列出所有架构并拦截
seccomp_arch_add(ctx, SCMP_ARCH_X86);
seccomp_arch_add(ctx, SCMP_ARCH_X86_64);
seccomp_arch_add(ctx, SCMP_ARCH_X32);
// 或使用 libseccomp 的架构中立名称(自动处理)
seccomp_rule_add(ctx, SCMP_ACT_ERRNO(EPERM), SCMP_SYS(openat), 0);
// libseccomp 会在规则设置时展开所有架构变体
8.2 vDSO 系统调用绕过
// vDSO(virtual Dynamic Shared Object)是内核提供的
// 用户空间系统调用加速机制。常见被加速的调用:
// - gettimeofday → 直接读取内核映射的共享数据
// - clock_gettime → 同上
// - time → 同上
// - getcpu → 同上
//
// 这些系统调用不经过传统 syscall 路径 → seccomp 无法拦截!
//
// 对策:
// 1. 在设计 seccomp 策略时,不依赖拦截时间获取调用
// 2. 对于安全关键场景,注意 vDSO 可能传递未授权信息
// 但是!Linux 5.0+ 可通过 vdso_call 追踪和限制
// 通过 /proc/self/vdso 的标记位 (vdso64_enabled) 禁用 vDSO
// (安全性 vs 性能权衡)
8.3 io_uring 与 seccomp 的交互
// io_uring 是一个特例:
// - io_uring_setup() 被 seccomp 拦截后
// - 但 io_uring_enter() / io_uring_register() 也可能被拦截
//
// 如果只拦截 io_uring_setup,用户可以:
// 1. 共享已有的 fd(从合法进程)
// 2. 使用 io_uring 执行任意文件 I/O
// → 绕过 seccomp 限制
// 安全做法(io_uring 沙箱化方案,Linux 6.x+):
// 1. 拦截所有 io_uring 相关系统调用
// 2. IORING_SETUP_SQES → 检查 SQ 条目内容
// 3. seccomp user notification 可代为 ckeck
//
// Linux 6.6+ 新增:
// IORING_SETUP_SUBMIT_ALL + 可审计的 SQ 内容
// 通过 BPF 程序审查 SQE 操作码
9. 未来方向:Linux 6.x 的 Seccomp 增强
9.1 Syscall Dispatcher(系统调用分发器)
Linux 6.x 引入的 syscall_user_dispatch 功能,允许用户空间接管系统调用处理:
// syscall_user_dispatch:将系统调用重定向到用户空间
// 参数:
// - offset: 用户空间区域起始地址(通常选择未映射地址)
// - length: 区域长度
// - flags: 配置位
// 工作模式:
// 1. 进程在区域内时 → 触发 SIGSYS(由用户捕获)
// 2. 进程不在区域内时 → 正常执行系统调用
// 应用场景:
// - 完全的用户空间系统调用处理(如 gVisor)
// - 选择性虚拟化特定系统调用
// - 与 seccomp notify 协同,实现零内核陷出的沙箱
9.2 BPF 化的 Seccomp 策略
上游正在讨论将 seccomp BPF 扩展为完整的 eBPF 程序:
// 未来(可能 Linux 7.x):eBPF 做 seccomp 决策
SEC("seccomp")
int seccomp_filter(struct seccomp_data *data) {
// 使用 eBPF maps 做动态策略查找
u64 pid = bpf_get_current_pid_tgid() >> 32;
u32 *policy = bpf_map_lookup_elem(&policy_map, &pid);
// BPF 可以访问:
// - Maps 中的动态策略数据库
// - 辅助函数(时间、随机数等)
// - 与外部分析系统交互
// - 审计结构化事件
if (policy & (1 << data->nr)) {
return SECCOMP_RET_ALLOW;
}
return SECCOMP_RET_LOG; // 记录后拒绝
}
// 好处:
// - 动态策略更新(无需重启进程)
// - 策略可跨进程共享
// - 细粒度审计(每个决策都可追踪)
10. 总结与最佳实践
seccomp-BPF 作为 Linux 容器安全的基石,已经从最初的四个系统调用白名单演进为强大的动态策略引擎。生产环境中构建安全沙箱的最佳实践包括:
- 使用 Runtime Default,按需扩展:从 Docker/K8s 默认策略开始,根据应用行为逐步调整
- 显式声明架构:始终包含 arch 检查,防止 32-bit ABI 绕过
- 限制参数而非仅限制调用:对 mmap、clone、ioctl 等参数化系统调用添加精确的参数过滤
- CRITICAL: 限制 unshare/setns/prctl:CAP_SYS_ADMIN 下的容器逃逸最常见向量
- 审计模式过渡:先用 SCMP_ACT_LOG 模式部署,观察策略影响后再切换到 ERRNO/TRAP
- 监控 io_uring 交互:如果使用 io_uring,确保其相关系统调用也被拦截
- Seccomp Notify 做动态沙箱:对于需要动态决策的场景,使用 Seccomp Notify 让 Supervisor 代为执行
seccomp-BPF 不是万能钥匙——它只是纵深防御体系中的一层。结合 namespaces、cgroups capabilities、AppArmor/SELinux 和正确的文件系统权限,才能构建真正的容器安全边界。

发表评论 取消回复