5.1 KiB
doos: Security Review
Date: 2026-10-23 | Reviewer: tai | Scope: src/*.cpp/*.hpp, CMakeLists.txt, Makefile, apparmor/doos, tests/run.sh, docs/*, SPEC.md
Build: C++17 CMake project ("doos" container/sandbox tool using user namespaces, cgroup v2, seccomp-bpf, pasta/slirp4netns networking, overlayfs).
Summary
Rootless container runtime with generally sound isolation primitives (user ns + idmap, pivot_root, cap-drop, seccomp denylist, no-new-privs, cgroup limits). Main risks: privileged helpers trusted via PATH (pasta, slirp4netns, newuidmap/newgidmap), TOCTOU-prone fs setup, permissive --hardening relaxed and --net host modes, and missing supply-chain/hardening controls (no SBOM/signing, no CI fuzz/scan, trivial AppArmor profile).
Findings (severity-ordered)
- [MEDIUM] PATH-based exec of network helpers:
src/network.cppexecspasta/slirp4netnsresolved via PATH; a poisoned PATH in attach path = code exec as the user. Mitigate with absolute paths + allowlist env scrub. - [MEDIUM] Symlink-following fs staging (TOCTOU):
src/sandbox.cpp:133-139mirrors host/etcentries withsymlink_status/read_symlinkthen recreates; bind source handling withoutO_NOFOLLOW/fd-relative ops invites race/escape. Useopenat2(RESOLVE_NO_SYMLINKS)or pin fds. - [MEDIUM]
relaxedmode silently drops most controls: percli.cpp:121, relaxed = no cap-drop, no seccomp, full/etc. Users likely won't grasp severity. Require explicit--i-understandflag + warning. - [MEDIUM] No integrity for images/layers:
src/image.cppuntars with numeric-owner handling but no digest/signature verification. Tampered tar = full container compromise. Add sha256 manifest check. - [LOW] Temp overlay upperdir via
mkdtempin shared TMPDIR:src/image.cpp:52usestemp_directory_path()(often/tmp, sticky but world-visible); predictable staging + 0700 chmod after the fact. Prefer per-user state dir withO_EXCL. - [LOW]
sscanfparsing of cgroup stat:src/container.cpp:231unchecked return; malformed file → stale values. Check return value. - [LOW] AppArmor profile is a stub:
apparmor/doos(12 lines) grants far less than runtime needs / isn't enforced by code. Either complete or remove to avoid false assurance. - [INFO] No seccomp allowlist, denylist only:
hardening.cppblocks keyring/bpf/perf/io_uring/mount/kexec/module-load; reasonable, but bypass surface remains (ptrace? userfaultfd covered). Document residual attack surface. - [INFO] No network egress policy: pasta/slirp give full user-mode egress; no DNS/TLS filtering. Expected for dev tool; document.
What is done well
- User-namespace-first, no setuid binary;
newuidmapdelegation preferred. NO_NEW_PRIVS+ capability bounding set to Docker-default keep-list./proc//sysremounts read-only, masked paths (kcore,keys), minimal/dev.- Cgroup v2
main/vsshell/split with freeze + rescue path is thoughtful anti-ransom design. pivot_root(not just chroot),umask,0700/0640perms on state.
Grades (0–10, 10=excellent)
| Category | Score | Rationale |
|---|---|---|
| Isolation & sandboxing | 7.5 | userns+pivot+cap-drop+seccomp+nonewprivs solid; weakened by relaxed mode, helper PATH trust |
| Filesystem security | 6.5 | Good perms/skeleton; symlink TOCTOU + /tmp staging + no dm-verity/readonly-root |
| Privilege & identity mgmt | 7.0 | No setuid, subuid mapping correct; host-uid file visibility nuance documented but subtle |
| Network security | 6.0 | User-mode net avoids root; no egress/filtering, PATH-exec helpers, --net host footgun |
| Resource controls (DoS) | 8.0 | cgroup v2 mem/pids/cpu + freeze model; best-effort when undelegated (fail-open must warn) |
| Input validation & parsing | 6.5 | CLI fixed-value flags good; tar/symlink handling + sscanf without strict checks |
| Secrets & state handling | 7.0 | State under DOOS_HOME with 0700; env (HOME/PATH) trusted too broadly |
| Supply chain & build | 5.0 | No SBOM, signing, pinning, CI SAST/fuzz; CMake clean but no -D_FORTIFY/-fstack-protector audit |
| Observability & audit | 5.5 | doos list table ok; no security event log, no seccomp-deny telemetry |
| Defaults & secure-by-default | 6.0 | Default mode good; relaxed/host modes one flag away with weak friction |
| Overall | 6.5 | Solid rootless dev-sandbox; fix PATH-exec, TOCTOU, image integrity before untrusted workloads |
Recommendations (prioritized)
- Absolute-path helpers + minimal sanitized env for all
execvp. openat2/ fd-pinned fs staging; fail closed on symlink races.- Image digest verification (sha256 manifest) before untar.
- Gate
relaxed/--net hostbehind explicit confirmation + log warning. - Harden build flags (
-Wall -Wextra -Werror -D_FORTIFY_SOURCE=3 -fstack-protector-strong -Wl,-z,RelRO,Now), add SBOM + CI (CodeQL/Semgrep/Trivy). - Check
sscanfreturns; move temp staging under state dir. - Finish or drop AppArmor profile; add seccomp-deny + OOM audit logging.
Verdict
Fit for trusted-dev use. Not yet recommended for running untrusted images/payloads until (1), (2), (3) are fixed.