当容器跑着不可信代码,系统调用就是最大的攻击面。seccomp-BPF 是 Linux 内核提供的"系统调用防火墙",它工作在 Ring 0 与 Ring 3 的边界上,以极简的 BPF 字节码实现最低成本的进程隔离。


一、从 Capabilities 到 seccomp:Linux 安全的"做减法"哲学

现代 Linux 安全遵循一个核心原则:最小特权(Least Privilege)。传统的 Unix 权限模型把进程分为"root"和"非 root"两类,root 可以做任何事,这导致容器技术早期的最大痛点——一个逃逸的容器进程几乎等价于宿主机沦陷。

为了解决这个问题,Linux 安全栈经历了三个阶段的演化:


Capabilities (2.2 )   ──►  seccomp (2.6.12 )   ──►  Landlock (5.13 )
    拆分特权                系统调用过滤                文件系统沙箱
  粗粒度权限              细粒度能力限制              细粒度资源访问

Capabilities 将 root 特权拆分为 40 个独立的 capability(如 CAP_NET_ADMIN、CAP_SYS_ADMIN),使得容器可以只保留所需的最小权限集。但 Capabilities 的问题在于:即使只剩 CAP_SYS_ADMIN,进程仍有数百个系统调用可用,攻击面依然庞大。

seccomp 的出现解决了这个问题:它从系统调用入口上直接限制进程的能力,无论进程拥有哪些 Capabilities,被 seccomp 过滤的系统调用都无法执行。


二、seccomp 架构解析:内核中的代码路径

2.1 系统调用流程中的拦截点

当用户态进程执行 syscall 指令时,CPU 从 Ring 3 切换到 Ring 0,内核的入口处理如下:


// arch/x86/entry/entry_64.S 简化流程
ENTRY(entry_SYSCALL_64)
    swapgs                          // 切换到内核 GS 基址
    movq    %rsp, PER_CPU_VAR(rsp_scratch)
    movq    PER_CPU_VAR(cpu_current_top_of_stack), %rsp
    
    // 构造 pt_regs 结构
    pushq   $__USER_DS              // SS
    pushq   PER_CPU_VAR(rsp_scratch) // RSP
    pushq   %r11                    // RFLAGS
    pushq   $__USER_CS              // CS
    pushq   %rcx                    // RIP
    ...
    call    do_syscall_64           // ← C 语言入口

// arch/x86/kernel/common.c
__visible noinstr void do_syscall_64(struct pt_regs *regs)
{
    // ① seccomp 检查点在这里
    if (secure_computing(regs)) {
        // 被过滤,记录并返回错误
        syscall_enter_from_user_mode(regs, regs-                        
                    
点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部