Watch
0
0
Fork
You've already forked hyperhive
0

check the container root before each start

This commit is contained in:
atlas 2026-10-28 20:57:27 +01:00 • committed by mara
commit a44a7256a7

View file

@ -12,7 +12,10 @@
# - the guest journal is written inside the container, where the agent's
# forwarder (nix/agent-modules/otel.nix) reads it, and the host can read it;
# - a package installed into the user's nix profile is still there, and on
# PATH, after a restart.
# PATH, after a restart;
# - a link planted at `root` in the template refuses the next start through
# the limits drop-in's `ExecStartPre=` check, leaves the link's target
# untouched, and the start goes through once the link is gone.
#
# The agent's journal forwarder itself (an OTLP push to the hive's collector) is
# not booted here; the module-eval suite covers its wiring.
@ -209,5 +212,38 @@ pkgs.testers.runNixOSTest {
assert len(salvages) == 1, salvages
host.succeed(f"ls -d {ROOT}.pre-ephemeral-* | wc -l | grep -x 1")
assert conf().count("--ephemeral") == 1, conf()
with subtest("a link planted in the root refuses the start and nothing is touched"):
stop()
# What hive-c0re does besides WriteNspawnFlags: the limits drop-in,
# which carries the pre-start check, and the runtime dir its condition
# names.
host.succeed(f"mkdir -p /run/hyperhive/agents/{AGENT}")
for req in [
{"op": "write_resource_limits", "container": MACHINE, "memory_max": "1G", "cpu_quota": "200%"},
{"op": "daemon_reload"},
]:
out = host.succeed(f"echo '{json.dumps(req)}' | socat - UNIX-CONNECT:/run/hive/priv.sock")
assert json.loads(out.strip().splitlines()[-1])["ok"] is True, out
dropin = host.succeed(f"cat /run/systemd/system/container@{MACHINE}.service.d/hyperhive-limits.conf")
assert "ExecStartPre=/nix/store/" in dropin and f"check-rootfs {MACHINE}\n" in dropin, dropin
# `root` is a link to a directory outside the root, which the start
# script would `chmod 0700` as host root.
victim = "/var/lib/victim"
host.succeed(f"mkdir -m 0755 {victim}")
host.succeed(f"rm -rf {ROOT}/root && ln -s {victim} {ROOT}/root")
host.fail(f"nixos-container start {MACHINE}")
host.succeed(
f"journalctl -u container@{MACHINE} | grep 'check-rootfs: refusing to start: {ROOT}/root is a symlink'"
)
assert host.succeed(f"stat -c %a {victim}").strip() == "755"
host.succeed(f"test -L {ROOT}/root")
# Control: with the link gone the same unit starts.
host.succeed(f"systemctl stop container@{MACHINE}")
host.succeed(f"systemctl reset-failed container@{MACHINE}")
host.succeed(f"rm {ROOT}/root && mkdir -m 0700 {ROOT}/root")
boot()
'';
}