fix: mask /proc info and selective /dev mounting#719
Conversation
Address Phase 3 filesystem exploit findings: 1. Mask /proc/kallsyms and /proc/modules in both container modes: - Non-chroot: Docker volume mounts /dev/null over /proc/kallsyms and /proc/modules - Chroot: bind-mount /dev/null over /host/proc/kallsyms and /host/proc/modules This prevents kernel symbol address disclosure (ASLR bypass) and module enumeration. 2. Replace blanket /dev:/host/dev:ro with selective device mounts in chroot mode: - Only mount /dev/null, /dev/zero, /dev/random, /dev/urandom, /dev/tty - Set up /dev/pts, /dev/shm, and standard symlinks (fd, stdin, stdout, stderr) in entrypoint This prevents host block device (/dev/sda*) exposure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
📰 DEVELOPING STORY: Smoke Copilot reports failed. Our correspondents are investigating the incident... |
|
💫 TO BE CONTINUED... Smoke Claude failed! Our hero faces unexpected challenges... |
|
Chroot tests failed Smoke Chroot failed - See logs for details. |
|
🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation... |
✅ Coverage Check PassedOverall Coverage
📁 Per-file Coverage Changes (1 files)
Coverage comparison generated by |
Security Review Complete ✅I've reviewed this PR for security implications. Overall, this PR strengthens the security posture by reducing the attack surface. Most changes are security improvements. Security Improvements ✅
Minor Security Consideration 🔍
mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null || trueThe world-writable shared memory space could theoretically be used for:
Severity: Low (contained within container, not shared with host) Potential hardening (may break some applications): mount -t tmpfs tmpfs /host/dev/shm -o mode=1770,size=64m,noexec 2>/dev/null || trueThis is a common pattern and necessary for many legitimate programs (Chrome, Python multiprocessing), so the current implementation is acceptable. Just documenting for awareness. ConclusionThis PR makes significant security improvements with no critical weaknesses. The
|
There was a problem hiding this comment.
Pull request overview
Implements additional container hardening to address filesystem exploit findings (#223) by masking kernel-info proc entries and reducing host device exposure in chroot mode.
Changes:
- Mask
/proc/kallsymsand/proc/modulesvia/dev/nullmounts (defense in depth across modes). - Replace chroot mode’s blanket
/dev:/host/dev:robind with an allowlist of essential device nodes, with additional/devsetup done in the agent entrypoint. - Update/add unit tests to assert the new mounts are present and the blanket
/devbind is removed in chroot mode.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/docker-manager.ts | Adds /proc masking volumes and switches chroot mode from blanket /dev bind to selective device mounts. |
| src/docker-manager.test.ts | Updates assertions and adds coverage for /proc masking and selective /dev mounts. |
| containers/agent/entrypoint.sh | Adds chroot-time masking for /host/proc/* and creates/mounts additional /host/dev entries (devpts, shm, stdio symlinks). |
Comments suppressed due to low confidence (1)
containers/agent/entrypoint.sh:188
mount -t devptsandmount -t tmpfsare attempted with|| true, but the script always prints that /dev/pts and /dev/shm are set up. If these mounts fail, many programs inside the chroot can behave incorrectly. Consider validating these mounts succeeded (or at least logging a warning and continuing intentionally).
mkdir -p /host/dev/pts /host/dev/shm
mount -t devpts devpts /host/dev/pts 2>/dev/null || true
mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null || true
# Standard /dev symlinks needed by many programs
ln -sf /proc/self/fd /host/dev/fd 2>/dev/null || true
ln -sf /proc/self/fd/0 /host/dev/stdin 2>/dev/null || true
ln -sf /proc/self/fd/1 /host/dev/stdout 2>/dev/null || true
ln -sf /proc/self/fd/2 /host/dev/stderr 2>/dev/null || true
echo "[entrypoint] Set up /dev/pts, /dev/shm, and standard symlinks in chroot"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| mount --bind /dev/null /host/proc/kallsyms 2>/dev/null || true | ||
| mount --bind /dev/null /host/proc/modules 2>/dev/null || true | ||
| echo "[entrypoint] Masked /proc/kallsyms and /proc/modules" | ||
|
|
||
| # Set up additional /dev entries in chroot (#223) | ||
| # Since /dev is selectively mounted (only null, zero, random, urandom, tty), | ||
| # we need to create pts, shm, and standard symlinks for proper operation | ||
| mkdir -p /host/dev/pts /host/dev/shm | ||
| mount -t devpts devpts /host/dev/pts 2>/dev/null || true | ||
| mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null || true | ||
| # Standard /dev symlinks needed by many programs | ||
| ln -sf /proc/self/fd /host/dev/fd 2>/dev/null || true | ||
| ln -sf /proc/self/fd/0 /host/dev/stdin 2>/dev/null || true | ||
| ln -sf /proc/self/fd/1 /host/dev/stdout 2>/dev/null || true | ||
| ln -sf /proc/self/fd/2 /host/dev/stderr 2>/dev/null || true | ||
| echo "[entrypoint] Set up /dev/pts, /dev/shm, and standard symlinks in chroot" | ||
|
|
There was a problem hiding this comment.
The /host/proc masking mounts ignore failures (|| true) but then always log "Masked /proc/kallsyms and /proc/modules". If either bind-mount fails, the container will still expose these proc entries while logs claim they’re masked. Please check each mount’s exit status and either fail closed or at least emit a clear WARN/ERROR when masking cannot be applied (and consider remounting the bind mount read-only if you want ro semantics).
This issue also appears on line 180 of the same file.
| mount --bind /dev/null /host/proc/kallsyms 2>/dev/null || true | |
| mount --bind /dev/null /host/proc/modules 2>/dev/null || true | |
| echo "[entrypoint] Masked /proc/kallsyms and /proc/modules" | |
| # Set up additional /dev entries in chroot (#223) | |
| # Since /dev is selectively mounted (only null, zero, random, urandom, tty), | |
| # we need to create pts, shm, and standard symlinks for proper operation | |
| mkdir -p /host/dev/pts /host/dev/shm | |
| mount -t devpts devpts /host/dev/pts 2>/dev/null || true | |
| mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null || true | |
| # Standard /dev symlinks needed by many programs | |
| ln -sf /proc/self/fd /host/dev/fd 2>/dev/null || true | |
| ln -sf /proc/self/fd/0 /host/dev/stdin 2>/dev/null || true | |
| ln -sf /proc/self/fd/1 /host/dev/stdout 2>/dev/null || true | |
| ln -sf /proc/self/fd/2 /host/dev/stderr 2>/dev/null || true | |
| echo "[entrypoint] Set up /dev/pts, /dev/shm, and standard symlinks in chroot" | |
| masked_kallsyms=0 | |
| masked_modules=0 | |
| if mount --bind /dev/null /host/proc/kallsyms 2>/dev/null; then | |
| # Optionally remount read-only to enforce ro semantics | |
| if ! mount -o remount,ro,bind /host/proc/kallsyms 2>/dev/null; then | |
| echo "[entrypoint][WARN] Masked /proc/kallsyms but failed to remount read-only; continuing with writable bind mount" | |
| fi | |
| masked_kallsyms=1 | |
| else | |
| echo "[entrypoint][WARN] Failed to mask /proc/kallsyms; kernel symbol information may be exposed in chroot" | |
| fi | |
| if mount --bind /dev/null /host/proc/modules 2>/dev/null; then | |
| # Optionally remount read-only to enforce ro semantics | |
| if ! mount -o remount,ro,bind /host/proc/modules 2>/dev/null; then | |
| echo "[entrypoint][WARN] Masked /proc/modules but failed to remount read-only; continuing with writable bind mount" | |
| fi | |
| masked_modules=1 | |
| else | |
| echo "[entrypoint][WARN] Failed to mask /proc/modules; kernel module list may be exposed in chroot" | |
| fi | |
| if [ "$masked_kallsyms" -eq 1 ] && [ "$masked_modules" -eq 1 ]; then | |
| echo "[entrypoint] Masked /proc/kallsyms and /proc/modules" | |
| else | |
| echo "[entrypoint][WARN] One or more sensitive /proc entries could not be masked (kallsyms=$masked_kallsyms, modules=$masked_modules)" | |
| fi | |
| # Set up additional /dev entries in chroot (#223) | |
| # Since /dev is selectively mounted (only null, zero, random, urandom, tty), | |
| # we need to create pts, shm, and standard symlinks for proper operation | |
| mkdir -p /host/dev/pts /host/dev/shm | |
| devpts_ok=0 | |
| shm_ok=0 | |
| if mount -t devpts devpts /host/dev/pts 2>/dev/null; then | |
| devpts_ok=1 | |
| else | |
| echo "[entrypoint][WARN] Failed to mount devpts at /host/dev/pts; pseudo-terminal support in chroot may be limited" | |
| fi | |
| if mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null; then | |
| shm_ok=1 | |
| else | |
| echo "[entrypoint][WARN] Failed to mount tmpfs at /host/dev/shm; shared memory in chroot may be unavailable" | |
| fi | |
| # Standard /dev symlinks needed by many programs | |
| ln -sf /proc/self/fd /host/dev/fd 2>/dev/null || true | |
| ln -sf /proc/self/fd/0 /host/dev/stdin 2>/dev/null || true | |
| ln -sf /proc/self/fd/1 /host/dev/stdout 2>/dev/null || true | |
| ln -sf /proc/self/fd/2 /host/dev/stderr 2>/dev/null || true | |
| if [ "$devpts_ok" -eq 1 ] && [ "$shm_ok" -eq 1 ]; then | |
| echo "[entrypoint] Set up /dev/pts, /dev/shm, and standard symlinks in chroot" | |
| else | |
| echo "[entrypoint][WARN] /dev/pts or /dev/shm could not be fully set up in chroot (devpts_ok=$devpts_ok, shm_ok=$shm_ok)" | |
| fi |
| mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null || true | ||
| # Standard /dev symlinks needed by many programs | ||
| ln -sf /proc/self/fd /host/dev/fd 2>/dev/null || true | ||
| ln -sf /proc/self/fd/0 /host/dev/stdin 2>/dev/null || true | ||
| ln -sf /proc/self/fd/1 /host/dev/stdout 2>/dev/null || true | ||
| ln -sf /proc/self/fd/2 /host/dev/stderr 2>/dev/null || true | ||
| echo "[entrypoint] Set up /dev/pts, /dev/shm, and standard symlinks in chroot" |
There was a problem hiding this comment.
Chroot mode mounts devpts at /host/dev/pts, but /host/dev/ptmx isn’t created/mounted here. Many programs expect /dev/ptmx (often a symlink to pts/ptmx) for pseudo-terminal allocation; without it, PTY-using commands can fail inside the chroot. Consider creating /host/dev/ptmx -> pts/ptmx alongside these standard /dev symlinks, or allowlist-bind-mount /dev/ptmx into /host/dev/ptmx.
| mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null || true | |
| # Standard /dev symlinks needed by many programs | |
| ln -sf /proc/self/fd /host/dev/fd 2>/dev/null || true | |
| ln -sf /proc/self/fd/0 /host/dev/stdin 2>/dev/null || true | |
| ln -sf /proc/self/fd/1 /host/dev/stdout 2>/dev/null || true | |
| ln -sf /proc/self/fd/2 /host/dev/stderr 2>/dev/null || true | |
| echo "[entrypoint] Set up /dev/pts, /dev/shm, and standard symlinks in chroot" | |
| # Provide /dev/ptmx inside the chroot as a symlink to pts/ptmx for PTY allocation | |
| ln -sf pts/ptmx /host/dev/ptmx 2>/dev/null || true | |
| mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null || true | |
| # Standard /dev symlinks needed by many programs | |
| ln -sf /proc/self/fd /host/dev/fd 2>/dev/null || true | |
| ln -sf /proc/self/fd/0 /host/dev/stdin 2>/dev/null || true | |
| ln -sf /proc/self/fd/1 /host/dev/stdout 2>/dev/null || true | |
| ln -sf /proc/self/fd/2 /host/dev/stderr 2>/dev/null || true | |
| echo "[entrypoint] Set up /dev/pts, /dev/ptmx, /dev/shm, and standard symlinks in chroot" |
| '/dev/zero:/host/dev/zero:rw', | ||
| '/dev/random:/host/dev/random:ro', | ||
| '/dev/urandom:/host/dev/urandom:ro', | ||
| '/dev/tty:/host/dev/tty:rw', |
There was a problem hiding this comment.
Selective /dev mounts in chroot mode omit /dev/ptmx. Since entrypoint.sh mounts devpts at /host/dev/pts, you typically also need /host/dev/ptmx (device or symlink to pts/ptmx) for PTY allocation. Without it, commands that allocate pseudo-terminals may fail inside the chroot. Add /dev/ptmx to the allowlist or ensure entrypoint creates the expected symlink.
| '/dev/tty:/host/dev/tty:rw', | |
| '/dev/tty:/host/dev/tty:rw', | |
| '/dev/ptmx:/host/dev/ptmx:rw', |
Summary
Fixes #223 (Phase 3 Filesystem Exploit Findings)
/proc/kallsymsand/proc/modulesin both container modes to prevent kernel symbol address disclosure (ASLR bypass) and kernel module enumeration/dev/nullover these paths/dev/nullover/host/proc/kallsymsand/host/proc/modulesafter procfs mount/dev:/host/dev:rowith selective device mounts in chroot mode to prevent host block device (/dev/sda*,/dev/nvme*) exposure/dev/null,/dev/zero,/dev/random,/dev/urandom,/dev/tty/dev/pts,/dev/shm, and standard symlinks (fd,stdin,stdout,stderr) in entrypoint.shTest plan
🤖 Generated with Claude Code