hyperhive/hive-priv
Repository files (latest commit first)
Filename Latest commit message Latest commit date
atlas a48e2f6977 fix(hive-priv): a stop that succeeds must actually release the machine name
`nixos-container stop` exiting 0 does not mean machined has dropped the
registration. A process sitting in the machine cgroup without being a
child of the container's init never receives the shutdown's SIGTERM if
it has been SIGSTOP'd, so the registration outlives the "successful"
stop. Every later start then fails with "Failed to register machine:
already exists", and machined re-persists the stale record across its
own restart, so there is no cleaning it up afterwards.

StopContainer now asks for the stop, waits for machined to release the
name, escalates to SIGKILL if it hasn't, re-verifies, and fails loudly
if the name is still held — so a caller is never told the stop worked
and then walks into the confusing registration error.

The probe resolves the name through machined's GetMachine, the same
lookup that later rejects the registration, rather than checking the
container's systemd unit: the unit going inactive while the name is
still held is precisely the case being caught.

Verify-and-escalate lives in the helper, not at a call site, so every
stop gets it — dashboard, reconcile, destroy, cold-start fallback. The
start path already distrusts its own exit code the same way; this is
the missing half of that pair.
2026-07-26 20:17:45 +02:00
..
src fix(hive-priv): a stop that succeeds must actually release the machine name 2026-07-26 20:17:45 +02:00
Cargo.toml docs(#2627): add READMEs for the remaining infra crates 2026-07-23 13:16:29 +02:00
README.md docs(#2627): add READMEs for the remaining infra crates 2026-07-23 13:16:29 +02:00

hive-priv

The minimal root privileged-helper for hive-c0re. It runs as root and exposes a narrow unix socket at /run/hive/priv.sock that accepts PrivRequest JSON lines and performs only the handful of operations that genuinely require root — bind-mount edits, nsenter into a container, btrfs subvolume ops. All coordination logic (broker, HTTP, scheduling) stays in the unprivileged hive-c0re process, which delegates here.

Why it exists

Privsep. hive-c0re runs as the unprivileged hive-core user so a bug or a prompt-injection in the large daemon can't directly wield root. The few root operations it needs are funnelled through this small, auditable helper instead. See docs/boundary.md and docs/security.md for the privilege boundary.

Security model

  • Strict allowlist. Every request is validated against a container-name allowlist before any filesystem or process operation — only names matching the hive convention (h-*, the manager container, known sibling service containers) are accepted.
  • No pass-through. Every PrivRequest variant maps to a single known operation; there is no arbitrary-command escape hatch.
  • Socket-activated, always. systemd binds /run/hive/priv.sock (SocketGroup=hive-core, 0660) and passes the listener as fd 3 (LISTEN_FDS); the helper requires this and has no self-bind fallback, so dev and prod take the identical path and the group grant always holds.

The wire contract (PrivRequest / response types) lives in the separate hive-priv-sock crate so this root binary depends on just the protocol shapes, not the whole daemon-shared crate.