A fork of opencontainers/runc for a bachelor's thesis: automatic generation of container security profiles (Linux capabilities, seccomp, AppArmor) from observed workload behavior.
Upstream runc docs: src/README.md. Implementation notes: .cursor/log/.
| Area | Change |
|---|---|
| Default posture | runc spec emits zero capabilities; containers start locked down unless you opt in |
| Legacy caps | --default-capabilities (3 caps, upstream) or --default-capabilities-docker (14 caps, Docker) — mutually exclusive |
--security-scan |
Learning mode: relax in-memory policy → trace → write narrowed profiles into config.json and generated/ |
apt update && apt install -y make gcc linux-libc-dev libseccomp-dev pkg-config git
make
sudo make install # → /usr/local/sbin/runc| Mode | Flag | Caps |
|---|---|---|
| Default | none | 0 |
| Upstream | --default-capabilities |
3 (CAP_AUDIT_WRITE, CAP_KILL, CAP_NET_BIND_SERVICE) |
| Docker legacy | --default-capabilities-docker |
14 |
runc run mycontainer # 0 caps
runc run --default-capabilities mycontainer # 3 caps
runc run --default-capabilities-docker mycontainer # 14 capsRequires cgroup v2, bpffs (/sys/fs/bpf), bpftool, capable-bpfcc with --cgroupmap, oci-seccomp-bpf-hook, and optionally AppArmor (without it MAC artifacts are file-only).
sudo script/setup-scan-host.shThe script installs packages, mounts bpffs, verifies tools, and creates user runcscan (uid/gid 65532) for non-root scans. oci-seccomp-bpf-hook must be installed separately (containers/oci-seccomp-bpf-hook).
cd /path/to/bundle
sudo runc run --security-scan mycontainerOverride auto-detected tool paths when needed: --scan-seccomp-hook PATH, --scan-capable PATH, --scan-bpftool PATH (a contrib stub exists for CI smoke).
For complete traces: run as a non-root uid (e.g. 65532), exercise every code path the production profile must cover, and rely on cgroup-wide tracing (children in the same cgroup are included via --cgroupmap).
- Relax (memory only) — clear
linux.seccomp,process.selinuxLabel,noNewPrivileges; grant allCAP_*; load complain-mode AppArmor stubrunc_scan_<id>. On-diskconfig.jsonuntouched until finalize. - Hooks — self-exec
runchooks (scan-aa-*,scan-cap-*) plus external prestartoci-seccomp-bpf-hook. No scripts are written into the bundle. - Run — workload executes; tracers record syscalls, capability checks, and AppArmor events.
- Poststop — stop
capable-bpfcc, unpin BPF map, collect AppArmor audit fromjournalctl -k(fallbackdmesg). - Finalize (successful exit only) — write narrowed policy into
config.json; back up the pre-scan spec once asgenerated/spec.original.json.
| File | Role |
|---|---|
seccomp.json |
OCI allow-list → linux.seccomp on finalize |
capable-bpfcc.log |
BCC trace → process.capabilities on finalize (replace, not merge; empty → empty) |
apparmor.profile |
Stub + audit rules; complain → enforce when rules were collected |
spec.original.json |
One-time backup of config.json before first finalize |
capabilities-from-proc-status.txt |
/proc/<init>/status snapshot — diagnostics only |
apparmor-load.log, apparmor-README.txt |
Load/unload logs and operator notes |
.runc_cap_trace.pid, .runc_aa_started_at |
Internal hook state |
SELinux profiles are not generated; an existing process.selinuxLabel is cleared only for the scan so tracing is not masked.
On success, config.json already has narrowed process.capabilities, linux.seccomp, and process.apparmorProfile set to runc_scan_<id>. A normal runc run then applies caps and seccomp through libcontainer; AppArmor auto-loads via apparmor_parser -r when the profile name starts with runc_scan_ and matches generated/apparmor.profile. Roll back by restoring generated/spec.original.json.
| Component | Files |
|---|---|
| Scan orchestration | src/scanner_linux.go |
| Self-exec OCI hooks | src/scanner_hooks_linux.go |
| Cgroup BPF map | src/scanner_bpf_linux.go |
| Finalize (caps, seccomp, AppArmor) | src/scanner_finalize_linux.go |
| AppArmor audit collection | src/scanner_apparmor_linux.go |
| Auto-load on normal run | src/scanner_apply_linux.go |
| Cap defaults / CLI wiring | src/utils_linux.go, libcontainer/specconv/example.go, src/run.go |
| Host provisioning | script/setup-scan-host.sh |
| CI stubs | contrib/runc-security-scan-stub-*.sh |
make test # unit + integration (upstream)
sudo make localintegration TESTPATH=/security_scan.bats # scanner smoke (root, stub hook)Apache 2.0 — same as upstream (LICENSE).