Skip to content

fix: mask /proc info and selective /dev mounting#719

Closed
Mossaka wants to merge 1 commit intomainfrom
fix/mask-proc-kallsyms-dev-hardening
Closed

fix: mask /proc info and selective /dev mounting#719
Mossaka wants to merge 1 commit intomainfrom
fix/mask-proc-kallsyms-dev-hardening

Conversation

@Mossaka
Copy link
Collaborator

@Mossaka Mossaka commented Feb 12, 2026

Summary

Fixes #223 (Phase 3 Filesystem Exploit Findings)

  • Mask /proc/kallsyms and /proc/modules in both container modes to prevent kernel symbol address disclosure (ASLR bypass) and kernel module enumeration
    • Non-chroot: Docker volume mounts /dev/null over these paths
    • Chroot: bind-mount /dev/null over /host/proc/kallsyms and /host/proc/modules after procfs mount
  • Replace blanket /dev:/host/dev:ro with selective device mounts in chroot mode to prevent host block device (/dev/sda*, /dev/nvme*) exposure
    • Only mount essential devices: /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.sh

Test plan

  • All 746 unit tests pass
  • Lint passes (0 errors)
  • Build succeeds
  • CI integration tests pass (monitor after merge)
  • If Fix 2 (selective /dev) breaks integration tests, revert to blanket mount with tmpfs overlays

🤖 Generated with Claude Code

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>
Copilot AI review requested due to automatic review settings February 12, 2026 05:27
@github-actions
Copy link
Contributor

github-actions bot commented Feb 12, 2026

📰 DEVELOPING STORY: Smoke Copilot reports failed. Our correspondents are investigating the incident...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 12, 2026

💫 TO BE CONTINUED... Smoke Claude failed! Our hero faces unexpected challenges...

@github-actions
Copy link
Contributor

github-actions bot commented Feb 12, 2026

Chroot tests failed Smoke Chroot failed - See logs for details.

@github-actions
Copy link
Contributor

github-actions bot commented Feb 12, 2026

🌑 The shadows whisper... Smoke Codex failed. The oracle requires further meditation...

@github-actions
Copy link
Contributor

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 82.25% 82.43% 📈 +0.18%
Statements 82.30% 82.48% 📈 +0.18%
Functions 82.14% 82.14% ➡️ +0.00%
Branches 74.70% 74.80% 📈 +0.10%
📁 Per-file Coverage Changes (1 files)
File Lines (Before → After) Statements (Before → After)
src/docker-manager.ts 83.5% → 84.2% (+0.74%) 82.9% → 83.7% (+0.72%)

Coverage comparison generated by scripts/ci/compare-coverage.ts

@Mossaka Mossaka closed this Feb 12, 2026
@github-actions
Copy link
Contributor

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 ✅

  1. /proc/kallsyms and /proc/modules masking (containers/agent/entrypoint.sh:170-175, src/docker-manager.ts:442-450)

    • Prevents kernel symbol address disclosure (ASLR bypass)
    • Prevents kernel module enumeration (exploit targeting)
    • Applied in both container and chroot modes (defense-in-depth)
  2. Selective /dev mounting (src/docker-manager.ts:468-492)

    • Replaces blanket /dev:/host/dev:ro with specific device nodes
    • Prevents exposure of host block devices (/dev/sda*, /dev/nvme*)
    • Only exposes: /dev/null, /dev/zero, /dev/random, /dev/urandom, /dev/tty
    • Significantly reduces attack surface for disk forensics and data exfiltration

Minor Security Consideration 🔍

/dev/shm mounted with mode 1777 (containers/agent/entrypoint.sh:182)

mount -t tmpfs tmpfs /host/dev/shm -o mode=1777 2>/dev/null || true

The world-writable shared memory space could theoretically be used for:

  • Inter-process communication between malicious code instances
  • Side-channel attacks via shared memory timing

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 || true

This is a common pattern and necessary for many legitimate programs (Chrome, Python multiprocessing), so the current implementation is acceptable. Just documenting for awareness.

Conclusion

This PR makes significant security improvements with no critical weaknesses. The /dev/shm consideration is minor and documented. Recommend approval from security perspective.

AI generated by Security Guard

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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/kallsyms and /proc/modules via /dev/null mounts (defense in depth across modes).
  • Replace chroot mode’s blanket /dev:/host/dev:ro bind with an allowlist of essential device nodes, with additional /dev setup done in the agent entrypoint.
  • Update/add unit tests to assert the new mounts are present and the blanket /dev bind 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 devpts and mount -t tmpfs are 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.

Comment on lines +173 to +189
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"

Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
Comment on lines +182 to +188
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"
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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"

Copilot uses AI. Check for mistakes.
'/dev/zero:/host/dev/zero:rw',
'/dev/random:/host/dev/random:ro',
'/dev/urandom:/host/dev/urandom:ro',
'/dev/tty:/host/dev/tty:rw',
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
'/dev/tty:/host/dev/tty:rw',
'/dev/tty:/host/dev/tty:rw',
'/dev/ptmx:/host/dev/ptmx:rw',

Copilot uses AI. Check for mistakes.
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