Firecracker 如何用 seccompiler-bin 把自定义 seccomp JSON 策略编译为二进制过滤器
【免费下载链接】firecrackerSecure and fast microVMs for serverless computing.项目地址: https://gitcode.com/GitHub_Trending/fi/firecracker
Firecracker 默认用 seccomp 过滤器限制进程可以使用的宿主机系统调用,默认过滤器在构建时由 seccompiler-bin 从 JSON 策略编译并嵌入 Firecracker 二进制。当需要使用实验性目标(如 GNU libc 构建)、debug 二进制,或者想临时调整某条系统调用规则而不重新构建 Firecracker 时,可以用同一套工具链在运行时提供自定义策略:先编写 seccomp JSON 文件,再用 seccompiler-bin 把它编译成二进制 BPF 过滤器,最后通过 Firecracker 的--seccomp-filter参数加载。seccompiler-bin 支持的目标架构是x86_64与aarch64,与 Firecracker 支持的平台范围一致。
准备条件
- Firecracker 源码树。seccompiler 是 cargo workspace 中的一个包,位于 src/seccompiler,其二进制 target 名为
seccompiler-bin(见 src/seccompiler/Cargo.toml),与 Firecracker 同一版本、同一发布节奏。 - 一份符合本文所述格式的 seccomp JSON 策略文件。
- 官方默认的过滤器 JSON 存放在 resources/seccomp,可以直接作为起点,例如 resources/seccomp/x86_64-unknown-linux-musl.json。
构建并查看 seccompiler-bin
在仓库根目录编译该二进制:
cargo build --bin seccompiler-bin查看完整命令行参数:
cargo run --bin seccompiler-bin -- --help命令行参数定义在 src/seccompiler/src/bin.rs:
| 参数 | 用途 |
|---|---|
--target-arch | BPF 程序运行的 CPU 架构,支持x86_64、aarch64 |
--input-file | JSON 策略文件路径 |
--output-file | 输出文件路径,缺省为seccomp_binary_filter.out |
--basic | 已废弃:丢弃所有参数检查,不推荐 |
--split-output | 为每个线程输出独立的原始 BPF 文件,用于测试 |
编写策略 JSON
一个 JSON 文件描述整个 Firecracker 进程的策略,针对单一目标平台。顶层对象把线程类别(vmm、api、vcpu)映射到各自的过滤器,每个过滤器包含default_action、filter_action和filter三个字段(格式详见 docs/seccompiler.md):
{ "vmm": { "default_action": "trap", "filter_action": "allow", "filter": [ { "syscall": "read" }, { "syscall": "write" } ] }, "api": { "default_action": "trap", "filter_action": "allow", "filter": [ { "syscall": "read" } ] }, "vcpu": { "default_action": "trap", "filter_action": "allow", "filter": [ { "syscall": "read" } ] } }字段语义:
default_action:没有任何规则匹配时执行的动作;filter_action:某条规则匹配后执行的动作。上例是典型的白名单写法(默认拒绝并触发trap,命中规则则允许)。filter是若干条规则(SyscallRule)的数组,规则之间是“或”关系,任一命中即触发filter_action。每条规则必须有syscall(系统调用名,不是架构相关的编号),可选comment,以及可选的args。args是一组“与”关系的条件对象,全部满足才算命中;缺省args时,只要调用名匹配就触发。条件对象必须有index(从 0 开始的参数下标)、type(dword为 4 字节、qword为 8 字节)、op(eq、ge、gt、le、lt、masked_eq、ne)、val(十进制整数),可选comment。- 动作(action)的取值来自 src/seccompiler/src/types.rs 中的枚举,以 snake_case 书写:
allow、log、trap、kill_thread、kill_process直接写为字符串,带数值的动作如errno、trace以对象形式书写(文档顶层示例写作"default_action": { "errno": -1 },属文档示例)。 - 同一系统调用若需要对不同参数组合分别放行,在
filter层级写多条规则即可。
带参数检查的规则示例(摘自 docs/seccompiler.md):
{ "syscall": "accept4", "args": [ { "index": 3, "type": "dword", "op": "eq", "val": 1, "comment": "libc::AF_UNIX" } ] }策略只支持数字常量,不支持具名参数;需要语义时用可选的comment字段说明。
编译过滤器
以自定义策略为例,在仓库根目录执行:
cargo run --bin seccompiler-bin -- \ --target-arch x86_64 \ --input-file my_policy.json \ --output-file my_filter.out如果已有编译好的二进制,等价写法为./seccompiler-bin --target-arch x86_64 --input-file my_policy.json --output-file my_filter.out(my_policy.json替换为你的策略文件)。
- 不指定
--output-file时,输出写到当前目录的seccomp_binary_filter.out。 --split-output会跳过合并输出,改为在输出文件同目录生成每个线程的<线程名>.bpf(如vmm.bpf、api.bpf、vcpu.bpf),内容是原始 BPF 字节码,文档标注其用途为测试。- 已废弃的
--basic会忽略所有args字段,不要在新策略中使用。
判断编译结果
成功时进程正常退出并生成输出文件。默认输出不是裸 BPF,而是 bitcode 序列化的“线程名 → BPF 指令序列”映射(见 docs/seccompiler.md 的 Output format 一节),因此cat出来是不可读内容,属正常现象;想看每个线程的原始 BPF,用--split-output。
失败时 src/seccompiler/src/lib.rs 定义了明确的错误文本,可据此定位问题:
Cannot parse arch: ...:--target-arch不是x86_64或aarch64。Cannot deserialize json: ...:JSON 结构不符合上述格式。Cannot add libseccomp syscall:某个系统调用名在指定架构下无法解析。Serialized BPF exceeds size limit of 100000 bytes:序列化产物超过 100000 字节上限。
用编译产物启动 Firecracker
编译出的文件通过 Firecracker 的可选参数--seccomp-filter提供,值为该二进制过滤器文件的路径(docs/seccomp.md 的 Custom filters 一节):
firecracker --seccomp-filter my_filter.out该参数与--no-seccomp互斥(见 src/firecracker/src/main.rs 中的参数定义)。过滤器在进程内按线程加载:VMM(主线程)在 VCPU 线程执行 guest 代码之前加载,API 线程在启动 HTTP 服务之前加载,VCPUs 在执行 guest 代码之前加载。如果过滤器加载失败,API 线程会报出Failed to set the requested seccomp filters on the API thread: ...,主流程会报出Failed to install vmm seccomp filter(见 src/firecracker/src/api_server/mod.rs 与 src/firecracker/src/main.rs)。
需要区分的是默认过滤器路径:构建 Firecracker 时,build 脚本会自动用 seccompiler 编译 resources/seccomp 下与目标对应的 JSON(debug 构建及缺失的目标文件则回退到 resources/seccomp/unimplemented.json),产物缓存到构建目录并在文件变更时重新编译(src/firecracker/build.rs)。运行时自定义过滤器与这条默认路径共用同一套 JSON/seccompiler 工具。
限制与注意
- 自定义过滤器会整体覆盖默认过滤器,官方标注这属于高级用法且有危险:配置错误可能导致进程被立即终止,或整个 seccomp 安全边界被禁用,官方推荐使用默认过滤器。
- 过滤器文件完全由用户负责管理;文档建议传输或下载文件(包括 Firecracker 二进制等产物)时使用校验和等完整性检查,以缓解中间人攻击风险。
- 文档给出的一个典型生产用例是:线上因某个未被策略允许的系统调用出现问题时,可用自定义过滤器快速缓解,但强调必须充分测试,且不应作为长期方案。
- debug 二进制与实验性 GNU 目标默认不安装 seccomp 过滤器(非生产用途),
--seccomp-filter正是这类场景下无需定制构建即可启用过滤的方式;其中 debug 与 release 构建的系统调用集合存在差异(例如 debug 断言会用到fcntl(F_GETFD)),编写策略时需注意。
如果只需要修改默认策略本身,直接编辑 resources/seccomp 下对应目标的 JSON 并重新构建 Firecracker,即可走默认过滤器的编译与嵌入流程。
【免费下载链接】firecrackerSecure and fast microVMs for serverless computing.项目地址: https://gitcode.com/GitHub_Trending/fi/firecracker
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考