From 419d0877022c9cfa886bfed3ed3ad901b583bc31 Mon Sep 17 00:00:00 2001 From: atlas Date: Fri, 6 Nov 2026 12:37:03 +0100 Subject: [PATCH] say the store check is an allowlist: only ext4, btrfs and xfs pass --- docs/agent-lifecycle/persistence.md | 12 ++++++++---- hive-priv/src/userns.rs | 13 +++++++------ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/docs/agent-lifecycle/persistence.md b/docs/agent-lifecycle/persistence.md index a271868a..a25d5b1d 100644 --- a/docs/agent-lifecycle/persistence.md +++ b/docs/agent-lifecycle/persistence.md @@ -489,10 +489,14 @@ hive-c0re can't read, or none, leaves the agent as it is. `claude/` dirs and its socket dir with `owneridmap`, and every other bind too (config, `/knowledge`, the runtime dir), whose owner shows as root inside. - **`/nix/store` has to be on ext4, btrfs or xfs.** nspawn mounts the store - into a namespaced container idmapped, which other filesystems (overlayfs, - tmpfs, older zfs) refuse. `WriteNspawnFlags` for an opted-in agent checks - the `statfs` type of `/nix/store` and fails with the type and the fix, - before it moves anything. Check a host with `findmnt -no FSTYPE /nix/store`. + into a namespaced container idmapped, and the kernel refuses that on + overlayfs and on some other filesystems. `WriteNspawnFlags` for an opted-in + agent checks the `statfs` type of `/nix/store` against an allowlist of those + three. The check refuses every other filesystem, zfs and tmpfs included, even + where a newer kernel could idmap it, because the gate exists to stop a + container that would not boot. The error names the type and the fix, and + comes before anything moves. Check a host with + `findmnt -no FSTYPE /nix/store`. - **The container starts with `--private-users=pick --private-users-ownership=map`.** nspawn idmaps the root at mount time, so a different range for `pick` never walks or chowns it. diff --git a/hive-priv/src/userns.rs b/hive-priv/src/userns.rs index dde13745..e96c3a35 100644 --- a/hive-priv/src/userns.rs +++ b/hive-priv/src/userns.rs @@ -51,7 +51,7 @@ const STORE: &str = "/nix/store"; type FsType = libc::__fsword_t; /// `f_type` of the filesystems that support idmapped mounts and that a store -/// can sit on: ext4, btrfs and xfs. +/// can sit on: ext4, btrfs and xfs. Nothing else is accepted. const IDMAP_FS: [FsType; 3] = [0xEF53, 0x9123_683E, 0x5846_5342]; /// The dirs under `/` the agent writes into. `config` @@ -111,18 +111,19 @@ fn fs_type(path: &Path) -> std::io::Result { Ok(buf.f_type) } -/// Refuse a store on a filesystem that cannot be idmapped: nspawn clones a +/// Refuse a store whose filesystem is not ext4, btrfs or xfs. nspawn clones a /// namespaced container's `/nix/store` bind with an idmap, which the kernel -/// refuses there, so the container would not boot. +/// refuses on other filesystems, so the container would not boot. Others are +/// refused even where a newer kernel could idmap them. fn check_store(agent: &str, f_type: std::io::Result) -> Result<()> { let f_type = f_type.with_context(|| format!("{agent}: statfs {STORE}"))?; if IDMAP_FS.contains(&f_type) { return Ok(()); } bail!( - "{agent} sets privateUsers, but {STORE} is on a filesystem (f_type {f_type:#x}) that \ - cannot be idmapped; move {STORE} to ext4, btrfs or xfs, or leave privateUsers off for \ - this agent" + "{agent} sets privateUsers, but {STORE} is on a filesystem (f_type {f_type:#x}) other \ + than ext4, btrfs or xfs, the only ones accepted; move {STORE} to one of them, or leave \ + privateUsers off for this agent" ) }