一、简介 

安全计算模式 seccomp(Secure Computing Mode)是自 Linux 2.6.10 之后引入到 kernel 的特性。一切都在内核中完成,不需要额外的上下文切换,所以不会造成性能问题。目前 在 Docker 和 Chrome 中广泛使用。使用 seccomp,可以定义系统调用白名单和黑名单,可以 定义出现非法系统调用时候的动作,比如结束进程或者使进程调用失败。

seccomp机制用于限制应用程序可以使用的系统调用,增加系统的安全性。

在/proc/${pid}/status文件中的Seccomp字段可以看到进程的Seccomp。

 二、prctl

下面程序使用prctl来设置程序的seccomp为strict模式,仅允许read、write、_exit和sigreturn四个系统调用。当调用未在seccomp白名单中的系统调用后,应用程序会被kill。

#include <stdio.h>
#include <sys/prctl.h>     /* prctl */
#include <linux/seccomp.h> /* seccomp's constants */
#include <unistd.h>        /* dup2: just for test */

int main() {
    printf("step 1: unrestricted\n");


    prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT);
    printf("step 2: only 'read', 'write', '_exit' and 'sigreturn' syscalls\n");

    // Redirect stderr to stdout
    dup2(1, 2);
    printf("step 3: !! YOU SHOULD NOT SEE ME !!\n");

    // Success (well, not so in this case...)
    return 0;
}

执行上述程序后会输出如下内容:

step 1: unrestricted
step 2: only 'read', 'write', '_exit' and 'sigreturn' syscalls
已杀死

 

三、基于BPF(伯克利分组过滤器)的seccomp

上述基于prctl系统调用的seccomp机制不够灵活,在linux 3.5之后引入了基于BPF的可定制的系统调用过滤功能。

需要先安装依赖包:

# Centos7
yum install libseccomp-devel
# Ubuntu
apt-get install libseccomp-dev
#include <stdio.h>   /* printf */
#include <unistd.h>  /* dup2: just for test */
#include <seccomp.h> /* libseccomp */

int main() {
  printf("step 1: unrestricted\n");

  // Init the filter
  scmp_filter_ctx ctx;
  ctx = seccomp_init(SCMP_ACT_KILL); // default action: kill

  // setup basic whitelist
  seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0);
  seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
  seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
  seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0);
  
  // setup our rule
  seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup2), 2, 
                        SCMP_A0(SCMP_CMP_EQ, 1),
                        SCMP_A1(SCMP_CMP_EQ, 2));

  // build and load the filter
  seccomp_load(ctx);
  printf("step 2: only 'write' and dup2(1, 2) syscalls\n");
  
  // Redirect stderr to stdout
  dup2(1, 2);
  printf("step 3: stderr redirected to stdout\n");

  // Duplicate stderr to arbitrary fd
  dup2(2, 42);
  printf("step 4: !! YOU SHOULD NOT SEE ME !!\n");

  // Success (well, not so in this case...)
  return 0; 
}

编译命令使用-l(小写L)参数链接第三方库,注意顺序,如果a依赖b,那么a应该放前面。

> gcc bpf-test.c -lseccomp -o bpf-test
> ./bpf-test; echo "Status: $?"

执行结果:

step 1: unrestricted
step 2: only 'write' and dup2(1, 2) syscalls
step 3: stderr redirected to stdout
错误的系统调用
Status: 159

 

四、docker中的应用

docker每个容器默认都设置了一个seccomp profile,屏蔽掉了其中的44个系统调用。

docker会将seccomp传递给runc中的sepc.linux.seccomp。

可以通过—security-opt seccomp=xxx来设置docker的seccomp策略,xxx为json格式的文件,其中定义了seccomp规则。

也可以通过--security-opt seccomp=unconfined来关闭docker引入默认的seccomp规则的限制。

 

ref

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐