seccomp接口用法及示例

seccomp(Secure Computing Mode)是 Linux 内核的安全机制,用于限制进程可用的系统调用(syscall),增强应用程序的安全性。以下是详细用法及示例:


核心接口

  1. prctl(PR_SET_SECCOMP, ...)
    传统模式,仅允许 read/write/exit/sigreturn 四种系统调用。
  2. seccomp(SECCOMP_SET_MODE_FILTER, ...)
    基于 BPF(Berkeley Packet Filter)的高级模式,支持自定义过滤规则。

示例 1:基础用法(C语言)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/prctl.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <linux/audit.h>

int main() {
// 设置传统 seccomp 模式(严格限制)
prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0); // 必需:禁止提权
prctl(PR_SET_SECCOMP, SECCOMP_MODE_STRICT); // 只允许 read/write/exit/sigreturn

printf("Hello, seccomp!\n"); // 允许,使用了 write 系统调用
// 若调用 fork(),进程会被终止(SIGKILL)

return 0;
}

示例 2:BPF 高级过滤(C语言)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <seccomp.h>
#include <unistd.h>

int main() {
scmp_filter_ctx ctx = seccomp_init(SCMP_ACT_KILL); // 默认策略:禁止所有系统调用

// 允许必要系统调用
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);
seccomp_release(ctx);

write(STDOUT_FILENO, "Filter applied!\n", 16);
// 若调用 fork(),进程会被终止
return 0;
}

示例 3:Python 使用 libseccomp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import ctypes
from ctypes.util import find_library

# 加载 libseccomp
libseccomp = ctypes.CDLL(find_library("seccomp"))

# 初始化过滤器
ctx = libseccomp.seccomp_init(0) # SCMP_ACT_KILL

# 允许 write 和 exit
libseccomp.seccomp_rule_add(ctx, 0x7fff0000, ctypes.c_int(1), 0) # SCMP_SYS(write)
libseccomp.seccomp_rule_add(ctx, 0x7fff0000, ctypes.c_int(231), 0) # SCMP_SYS(exit_group)

# 加载过滤器
libseccomp.seccomp_load(ctx)
print("Filter active! Try calling os.fork() to test.")

关键步骤

  1. 初始化上下文
    • seccomp_init(SCMP_ACT_KILL):默认拒绝所有调用。
  2. 添加规则
    • seccomp_rule_add(ctx, action, syscall, arg_cnt, ...):允许/拒绝特定系统调用。
  3. 加载过滤器
    • seccomp_load(ctx):应用规则到当前进程。
  4. 释放资源
    • seccomp_release(ctx):清理上下文。

常用系统调用编号

调用名 编号 说明
read 0 读取文件
write 1 写入文件
exit 60 退出进程
exit_group 231 退出所有线程
openat 257 打开文件

通过 grep -r "SYSCALL_NAME" /usr/include/ 查找编号。


注意事项

  • 禁止提权:必须先调用 prctl(PR_SET_NO_NEW_PRIVS, 1)
  • 多线程:需在主线程设置,子线程继承规则。
  • 调试:使用 SCMP_ACT_TRAP 替代 KILL,捕获 SIGSYS 信号调试规则。
  • 容器支持:Docker 等容器默认启用 seccomp,配置文件位于 /etc/docker/seccomp.json

通过合理配置 seccomp,可显著减少应用程序的攻击面,提升系统安全性。