hive-priv: fix stale 0750 in the tmpfiles.d /run/hyperhive entry

sync_agent_tmpfiles wrote 'd /run/hyperhive 0750 hive-core hive-core -' into
/etc/tmpfiles.d/hyperhive-agents.conf on every agent spawn/destroy -- five
months after 30a2a2e9 moved the directory to 0751 so hive-admin members
(no hive-core membership) can traverse into it to reach host.sock.

the 0750 write itself always EROFSes (hive-priv's ReadWritePaths doesn't
include /run/hyperhive, tracked separately as #4194 -- do not 'fix' that
by adding it there, since a *succeeding* 0750 write would permanently
break traversal on every host). so the directory only ever stayed at the
correct 0751 by accident, preserved by a failing privileged call, and any
mechanism that ever recreates the dir at the old baked-in RuntimeDirectoryMode
default would un-mask this instantly. matching the tmpfiles line to 0751
removes the wrong write entirely: no mode to change, no fchmod, no EROFS.

root cause found by atlas, digging in from the other end while verifying
boundary.md's permission numbers against the running host. credit is
entirely theirs -- I'd been chasing reboot-vs-restart theories on the
issue thread without finding this.

fixes #4078
This commit is contained in:
damocles 2026-09-11 08:22:12 +02:00 committed by mara
commit 9a94fa08e3

View file

@ -3019,7 +3019,17 @@ async fn sync_agent_tmpfiles(agents: &[AgentTmpfilesEntry]) -> Result<(String, S
// Parent dirs — created with permissive mode so hive-c0re can make subdirs. // Parent dirs — created with permissive mode so hive-c0re can make subdirs.
// /run/hyperhive itself is also a RuntimeDirectory of hive-c0re.service; the // /run/hyperhive itself is also a RuntimeDirectory of hive-c0re.service; the
// tmpfiles.d entry here ensures it exists before hive-c0re starts (boot race). // tmpfiles.d entry here ensures it exists before hive-c0re starts (boot race).
content.push_str("d /run/hyperhive 0750 hive-core hive-core -\n"); //
// 0751, not 0750: must match hive-c0re.service's own `RuntimeDirectoryMode`
// and `docs/trust-boundary/boundary.md` — the extra `--x` on `other` is what
// lets a `hive-admin`-only user (no `hive-core` membership) traverse into the
// directory to reach `host.sock`; without it that user gets a permission
// denied opening the socket despite correct group membership on the socket
// itself. A mismatch here isn't just cosmetic: this line is regenerated and
// re-applied on every agent spawn/destroy via `systemd-tmpfiles --create`,
// so a stale `0750` here actively re-asserts the old, wrong mode far more
// often than a reboot does.
content.push_str("d /run/hyperhive 0751 hive-core hive-core -\n");
writeln!(content, "d {AGENT_RUNTIME_ROOT} 0755 hive-core hive-core -").ok(); writeln!(content, "d {AGENT_RUNTIME_ROOT} 0755 hive-core hive-core -").ok();
// `hive-core`, not root: c0re does the `create_dir_all` for a new agent's // `hive-core`, not root: c0re does the `create_dir_all` for a new agent's
// subdir itself, so a root-owned parent EACCESes on the first spawn of a // subdir itself, so a root-owned parent EACCESes on the first spawn of a