Skip to content

refactor(firma-run): compile managed seccomp BPF via seccompiler - #415

Draft
lu-zero wants to merge 1 commit into
Firma-AI:mainfrom
lu-zero:seccomp/seccompiler-release
Draft

refactor(firma-run): compile managed seccomp BPF via seccompiler#415
lu-zero wants to merge 1 commit into
Firma-AI:mainfrom
lu-zero:seccomp/seccompiler-release

Conversation

@lu-zero

@lu-zero lu-zero commented Aug 1, 2026

Copy link
Copy Markdown

Why

crates/firma-run/src/seccomp.rs hand-emits classic-BPF opcodes byte-by-byte
(manual LD/JMP/RET encoding, manual arch-check prologue). That's the
riskiest part of the file to review and extend by hand. This is draft 1 of 2
evaluating a port to the seccompiler
crate (rust-vmm/Firecracker) as the BPF compiler backend; draft 2 will follow
up with a fork that adds public syscall-name-to-number resolution.

What Changed

  • Replace emit_bpf_program/emit_stmt/emit_jump and the local
    TargetArch enum with seccompiler::SeccompFilter/SeccompAction/
    TargetArch, which generate the arch-check prologue and per-syscall jump
    table.
  • Keep the existing hand-maintained SyscallId::number_for_arch per-arch
    syscall-number table as-is (released seccompiler has no public
    name-to-number resolution yet — that's what draft 2 addresses).
  • Serialize the compiled Vec<sock_filter> to the same raw byte layout
    (u16 code, u8 jt, u8 jf, u32 k, native endian) the artifact file
    and bwrap --seccomp <fd> already expect, so the artifact/metadata/
    checksum contract in linux-local-command-enforcement.md is unchanged.
  • Bump compiler_version to managed-seccomp-v2-seccompiler since the
    emitted BPF byte sequence differs from the hand-rolled emitter (same
    semantics, different instruction encoding from seccompiler's compiler).

Manual / Extra Verification

  • Ran on an aarch64 Linux host: scripts/seccomp/check-managed-compatibility.sh passes.
  • cargo nextest run -p firma-run (384 tests) passes, including the existing
    BPF-reproducibility test (compile_on_launch_is_reproducible_for_same_policy_and_arch)
    unmodified.

Risks / Notes

  • No config, wire-format, or policy-input change. The set of denied syscalls
    per action class is identical; only how the BPF bytes for that deny-list
    get generated changed.
  • Adds seccompiler (Apache-2.0 OR BSD-3-Clause, pure Rust, no system/link
    dependency) as a Linux-only dependency of firma-run.
  • Confirmed dprint check is clean for every file this PR touches
    (Cargo.toml, crates/firma-run/Cargo.toml, crates/firma-run/src/seccomp.rs,
    docs/architecture/linux-local-command-enforcement.md). just fmt still
    fails repo-wide on 10 pre-existing files under todo/, unrelated to this
    change and already failing on main.

AI Assistance

Implemented with Claude Sonnet 5 (Claude Code) per explicit user request, after a
prior conversation turn reviewed the current seccomp implementation and
evaluated seccompiler vs libseccomp as replacement backends.

Replace the hand-emitted classic-BPF opcode encoder in seccomp.rs with
the seccompiler crate (rust-vmm/Firecracker). seccompiler handles the
arch-check prologue and per-syscall jump table construction; the
per-arch syscall-number table and the artifact/metadata/checksum
contract are unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@lu-zero
lu-zero force-pushed the seccomp/seccompiler-release branch from ec5c6b7 to dfdc5d0 Compare August 1, 2026 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant