seccomp 让进程自己限制自己能用哪些系统调用——容器、浏览器、沙箱的核心安全机制。
一、先看图
flowchart TD
APP[应用程序] -->|prctl / seccomp| FILTER[BPF 过滤器<br/>系统调用白名单]
APP -->|syscall| CHECK{seccomp 检查}
CHECK -- 允许 --> EXEC[执行 syscall]
CHECK -- 拒绝 --> ACTION[KILL / ERRNO / TRACE / LOG]
LL[Landlock] -->|自限| FS[文件系统访问<br/>路径级控制]
classDef allow fill:#3fb95022,stroke:#3fb950,color:#adbac7;
classDef deny fill:#f8514922,stroke:#f85149,color:#adbac7;
class APP,FILTER,CHECK allow
class ACTION deny
class LL,FS allow
二、seccomp 模式
2.1 Strict Mode
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
// 之后只允许:read, write, exit, sigreturn太严格 → 几乎没人用。
2.2 Filter Mode(seccomp-bpf)
struct sock_filter filter[] = {
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_write, 0, 1),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),
};
struct sock_fprog prog = { .len = 4, .filter = filter };
prctl(PR_SET_NO_NEW_PRIVS, 1);
prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);BPF 程序检查每个系统调用 → 决定允许/拒绝/记录。
三、过滤动作
| 动作 | 效果 |
|---|---|
| SECCOMP_RET_ALLOW | 允许 |
| SECCOMP_RET_KILL_PROCESS | 终止进程 |
| SECCOMP_RET_KILL_THREAD | 终止线程 |
| SECCOMP_RET_ERRNO | 返回错误码 |
| SECCOMP_RET_TRACE | 通知 ptrace |
| SECCOMP_RET_LOG | 允许但记录 |
| SECCOMP_RET_USER_NOTIF | 通知用户态 |
四、User Notification
SECCOMP_RET_USER_NOTIF → 系统调用暂停 → supervisor 进程决定容器 runtime 用这个实现:进程请求 mount → seccomp 拦截 → runtime 代为执行。
五、容器中的 seccomp
Docker 默认 seccomp profile 禁止危险 syscall:
docker run --security-opt seccomp=my-profile.json my_app默认禁止:mount, reboot,
kexec_load, bpf 等。
六、Landlock
seccomp 按系统调用过滤 → Landlock 按路径过滤:
struct landlock_ruleset_attr attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE |
LANDLOCK_ACCESS_FS_WRITE_FILE,
};
int ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0);
struct landlock_path_beneath_attr path_attr = {
.allowed_access = LANDLOCK_ACCESS_FS_READ_FILE,
.parent_fd = open("/usr", O_PATH),
};
landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, &path_attr, 0);
landlock_restrict_self(ruleset_fd, 0);
// 之后只能读 /usr 下的文件非特权进程可用 → 不需要 root。
七、Syscall User Dispatch
prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON,
start, len, &selector);syscall 在指定地址范围外 → 发送 SIGSYS → 用户态处理。
用途:Wine/WSL 风格的系统调用翻译。
八、libseccomp
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit_group), 0);
seccomp_load(ctx);高级 API → 不需要手写 BPF 字节码。
九、观察
# 检查进程 seccomp 状态
grep Seccomp /proc/self/status
# 0=disabled, 1=strict, 2=filter
# 审计日志
ausearch -m seccomp
# Landlock 支持
cat /sys/kernel/security/landlock/abi_version
# Docker seccomp profile
docker inspect --format '{{.HostConfig.SecurityOpt}}' container_id十、小结
- seccomp-bpf = 系统调用级别的过滤 → 容器安全基础
- User Notification 让 supervisor 代为处理被拦截的 syscall
- Landlock = 路径级别的访问控制 → 非特权进程可用
- libseccomp 简化 BPF 过滤器编写
参考文献
kernel/seccomp.csecurity/landlock/man 2 seccompman 7 landlock
工具
libseccomp- Docker seccomp profiles
ausearch -m seccomp
上一篇:POSIX capabilities 下一篇:SELinux 与 AppArmor
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【操作系统百科】内核与用户态的边界:copy_from_user、pin、seccomp、capability
内核代码不能像用户代码那样自由访问任何指针。本文围绕 Linux 的 access_ok / copy_from_user / get_user_pages / pin_user_pages / __user 注解,说明用户页在内核视角的生命周期;再把视角扩展到 capability、namespace、seccomp、Landlock、LSM 等软件边界机制,汇成一张内核对用户态信任的全景图。
【操作系统百科】POSIX capabilities
为什么 setuid root 早该被 capabilities 取代?cap sets(permitted/effective/inheritable/bounding/ambient)、file caps、容器内 capabilities——本文讲 Linux 的细粒度权限模型。
【操作系统百科】内存回收
Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。
【操作系统百科】交换
swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。