Skip to content

Rootless userns#166

Draft
Mic92 wants to merge 4 commits intomainfrom
rootless-userns
Draft

Rootless userns#166
Mic92 wants to merge 4 commits intomainfrom
rootless-userns

Conversation

@Mic92
Copy link
Copy Markdown
Member

@Mic92 Mic92 commented Mar 27, 2026

Add back single user installations. Currently only the script-based installer features this. Having this feature unlocks tools like this: https://github.com/nix-community/nix-user-chroot

Mic92 added 4 commits March 27, 2026 09:26
set_nix_options runs nix before the user has sourced any profile
script, and when --skip-nix-conf (or a custom NIX_CONF_DIR) is in
play the experimental-features line we'd normally have placed in
/etc/nix/nix.conf isn't there. The compiled-in default also sets
build-users-group=nixbld, which errors out if that group wasn't
created.

Pass both as explicit --option args so profile setup stands on its
own regardless of what nix.conf says or where it lives.
With --nix-build-user-count 0 the nixbld group never exists, so the
ensure_nix_store_group pass just emits a WARN per store path as each
lchown to gid 30000 fails. Inside a single-uid user namespace it
fails with EINVAL rather than EPERM, which looks alarming even
though it's harmless.

Represent the gid as Option<u32> and skip the pass entirely when
there's nothing to chown to.
Tools like nix-user-chroot and toolbox set up an unprivileged user
namespace where /nix is a bind mount into the user's home and /etc
is a read-only view of the host. Only one uid/gid is mapped, so
groupadd can't allocate gid 30000 and any write under /etc fails
with EROFS.

The individual knobs to avoid those writes mostly exist already
(--no-modify-profile, --skip-nix-conf, --init none) but
CreateUsersAndGroups runs unconditionally and a few /etc paths
(tmpfiles.d, the Arch BASH_ENV snippet) aren't gated on anything.

--rootless sets the right combination and closes the remaining gaps,
giving an install that touches nothing outside /nix. Also gate
CreateUsersAndGroups on nix_build_user_count > 0 independently,
since a zero count with an unconditional groupadd is just wrong on
its own.
Two consumers of planner settings were reading pre-resolution values:

daemon_expected() checked settings.get("init") but the linux
planner's settings() returned the raw clap-parsed InitSettings, so
--rootless (which resolves to init=none internally) still looked
like systemd and triggered a 10s poll for a socket that would never
appear.

The self-test execs 'sh -lc nix build ...', which only works if we
wrote the shell profile hooks that put nix on PATH.
--no-modify-profile (implied by --rootless) intentionally skips
those, so the test just reports 'nix: not found' against a working
install.

Make settings() return resolved values, and gate the self-test on
modify_profile.
@Mic92 Mic92 marked this pull request as draft March 27, 2026 09:23
Mic92 added a commit to nix-community/nix-user-chroot that referenced this pull request Mar 27, 2026
Collapses the two-step mkdir + curl-pipe-sh dance from the README
into a single command. Defaults the store location to
$XDG_DATA_HOME/nix and runs the NixOS nix-installer inside our user
namespace with its new --rootless mode, so it sees a writable /nix
without any real privilege.

The uid mapping for --install writes '0 <uid> 1' instead of the
usual identity map so the installer's EUID==0 checks pass; everything
it creates still lands as the real user on the host filesystem since
only one uid is mapped.

The installer binary is fetched via curl to keep the normal
(network-free) operation of nix-user-chroot from gaining an HTTP+TLS
dependency. NIX_USER_CHROOT_INSTALLER lets tests and offline users
point at a local binary instead.

wait_for_child now returns the exit status rather than calling
process::exit directly, so the parent can print the 'enter with...'
hint only on a successful install.

Depends on NixOS/nix-installer#166 for the
--rootless flag.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant