fix(serve): drop ProtectHome — was blocking SSH peer probe

The v0.2.0 unit set ProtectHome=true to lock down /home from a
hypothetical RCE in axum. Side effect: ssh in peer_reachable
(serve.rs:145) failed with "Host key verification failed: Permission
denied" because ~/.ssh/known_hosts was unreachable. Adding
BindReadOnlyPaths=/home/osobh/.ssh didn't help — systemd applies
ProtectHome before the bind mounts run, so /home is already an
inaccessible barrier when the bind lands. Result: both dashboards
showed peer_reachable=false even though LAN ping + SSH worked fine
from a shell.

Two options to keep some sandboxing:
  1. ProtectHome=tmpfs + BindReadOnlyPaths=/home/osobh/.ssh — bind
     into an empty tmpfs view of /home.
  2. Drop ProtectHome entirely — keep ProtectSystem=strict +
     ReadWritePaths=/var/lib/claw-store + NoNewPrivileges + PrivateTmp.

Going with (2) for now. The threat model is local-host RCE in a
read-mostly axum service the dashboard pokes; ProtectSystem alone
prevents writing anywhere outside /var/lib/claw-store. Re-introduce
(1) when we have a clean justification.

Co-Authored-By: Claude Opus 4.7 <[email protected]>
This commit is contained in:
Omar Sobh
2026-06-28 13:08:02 +00:00
co-authored by Claude Opus 4.7
parent af50adec19
commit d5651614ba
+8 -4
View File
@@ -16,12 +16,16 @@ Restart=on-failure
RestartSec=15 RestartSec=15
Environment=RUST_LOG=info Environment=RUST_LOG=info
# Dashboard is read-mostly + shells out to the local CLI for mutations; # Dashboard is read-mostly + shells out to the local CLI for mutations
# no network egress / no privileged ops needed. Lock down what we don't # AND probes the peer over SSH for /api/status's peer_reachable bit.
# use so a future RCE in axum can't pivot. # Notes on the sandboxing:
# - ProtectHome was tried (with BindReadOnlyPaths=/home/osobh/.ssh)
# but systemd blocks ALL of /home before binds run; the ssh probe
# hits "Permission denied" on ~/.ssh/known_hosts even with the
# bind. Re-introduce via ProtectHome=tmpfs + an explicit bind if
# stronger sandboxing is needed later.
ProtectSystem=strict ProtectSystem=strict
ReadWritePaths=/var/lib/claw-store ReadWritePaths=/var/lib/claw-store
ProtectHome=true
NoNewPrivileges=true NoNewPrivileges=true
PrivateTmp=true PrivateTmp=true