From c3533b3abd6820dc14d3fbb4073e38a7c35ef2d0 Mon Sep 17 00:00:00 2001 From: Ben Barclay Date: Fri, 21 Aug 2026 07:33:49 +1000 Subject: [PATCH] review: harden flaps socket grant (symlink guard, verified outcome, precise scope note) Address sol-reviewer findings: route the mutation through the existing refuse_symlinked_path helper (consistency with the script's CWE-59 protections), only print success when both chgrp and chmod actually succeeded (warn otherwise instead of a false-positive boot log), fix the lifecycle wording (this hook runs after the supervision tree is up, before user services), and state the widening scope precisely: the whole local Machines API becomes group-writable, accepted because the agent already runs arbitrary user code as the same principal. --- docker/stage2-hook.sh | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/docker/stage2-hook.sh b/docker/stage2-hook.sh index 5844d4ff41..a07b8eec31 100755 --- a/docker/stage2-hook.sh +++ b/docker/stage2-hook.sh @@ -476,14 +476,21 @@ fi # (gateway/scale_to_zero.py suspend_self) must POST to it, but the gateway runs # as the unprivileged `hermes` user — without this it gets EACCES on every # suspend attempt and the machine can never sleep (fail-awake; verified live on -# staging 2026-08-20: "flaps suspend request failed: [Errno 13]"). stage2 runs -# as root before the supervision tree starts, so grant group access here. -# Group-write is the minimal widening: the socket stays root-owned and -# non-hermes users gain nothing. No-op off Fly (socket absent). +# staging 2026-08-20: "flaps suspend request failed: [Errno 13]"). This hook +# runs as root before user services (the gateway) start, so grant group access +# here. Scope note: group-write exposes the WHOLE local Machines API to the +# hermes group (any group member could e.g. stop/suspend this machine), not +# just the suspend endpoint — accepted because the agent already executes +# arbitrary user code as that same principal and the socket only controls THIS +# machine. No-op off Fly (socket absent). if [ -S /.fly/api ]; then - chgrp hermes /.fly/api 2>/dev/null || true - chmod g+w /.fly/api 2>/dev/null || true - echo "[stage2] Granted hermes group access to the Fly Machines API socket" + if refuse_symlinked_path "chgrp/chmod" /.fly/api; then + : + elif chgrp hermes /.fly/api 2>/dev/null && chmod g+w /.fly/api 2>/dev/null; then + echo "[stage2] Granted hermes group access to the Fly Machines API socket" + else + echo "[stage2] Warning: could not grant group access to /.fly/api — scale-to-zero self-suspend will fail EACCES (fail-awake)" + fi fi # --- Migrate persisted config schema ---