Internal/advisory seccomp JSON (--seccomp-out)
This output belongs to --seccomp-source=internal. In SPO mode, SPO owns
syscall observation and derives the SeccompProfile; --seccomp-out is
rejected rather than presenting SPO-derived policy as landlock-genprof
observation.
Pass --seccomp-out to generate a plain advisory profile from the same
training run (skipped if no syscalls were observed), via Inspektor
Gadget’s own advise_seccomp gadget (see Step 2’s gadget table):
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["accept4", "capget", "capset", "chdir", "epoll_wait", "futex", "openat", "read", "write"],
"action": "SCMP_ACT_ALLOW"
}
]
}
capget, capset, chdir, and futex are always folded in alongside
whatever was actually traced — none of the four is something the traced
binary itself calls, but the container runtime (runc) needs all of them
during container init, before it even execs into the binary. Confirmed
live (2026-07-30) one at a time, each the next crash after fixing the
last, all inside runc’s own finalizeNamespace
(libcontainer/init_linux.go), called in this exact order:
capget— a kernel-capability-version probe. Without it:OCI runtime create failed: ... unable to get capability version from the kernel: operation not permitted.futex— runc’s own init is itself written in Go, and the Go runtime’s scheduler/GC depend on futex(2) for their whole lifetime, not just one step. Without it, the container gets created but crashes immediately (cannot start a stopped process),kubectl logs --previousshowing a raw Go runtime panic (“The futex facility returned an unexpected error code”) insidelibcontainer.setupUser/finalizeNamespace.chdir— sets the container’s configured working directory. Without it:OCI runtime create failed: ... chdir to cwd ("/") set in config.json failed: operation not permitted.capset— applies thesecurityContext.capabilitiesevery patched manifest this project generates sets explicitly (internal/exporter/capabilities). Predicted rather than independently confirmed by its own distinct crash (it’s the very next callfinalizeNamespacemakes afterchdir) — if a live test still crash-loops with a different error after this, that prediction was wrong.
A trace of the traced binary’s own behavior can never observe any of these, since all four happen in a separate process phase before exec.
Deliberately plain JSON, not YAML with a # confidence: ... comment like
the other two outputs: this file is loaded directly by the kubelet/
container runtime (referenced via a pod’s
securityContext.seccompProfile.localhostProfile, never kubectl applyd), so it has to stay valid, comment-free JSON. Instead, the CLI
prints the syscalls not yet confirmed across multiple --history runs to
stdout after writing the file — on a single run without --history, that
means every syscall, since advise_seccomp reports one deduplicated set
per run rather than a per-occurrence count, so Confidence can only ever
be low until --history accumulates more runs.
This standalone file has no proposal authority on its own. It is worth taking seriously before enforcing: a missing syscall
doesn’t just narrow access like an overly-strict NetworkPolicy would —
it breaks the container outright. Prefer --history over a single internal
run, then use the governed proposal workflow rather than treating confidence
as authorization.