Subject: Re: bug#75810: [PATCH 0/6] Rootless guix-daemon

From: Ludovic Courtès <[email-masked]>
Date: Wed, 12 Mar 2025 23:27:54 +0100

Hi,

Reepca Russelstein <[email-masked]> skribis:

>> For some reason, it’s not working as advertised: mounts are seemingly
>> not locked together and umount(2) on one of them returns EPERM (instead
>> of EINVAL).  I suspect chroot, pivot_root, & co. spoil it all.
>
> What this shows is that we're not currently testing the mount-locking
> because the builder lacks the necessary capability in its user namespace
> (this capability was removed from the effective set when the builder was
> exec'ed).  That is, the kernel doesn't get as far as checking whether
> the mount is locked because the caller wouldn't have the permission to
> unmount it even if it weren't locked.

Oh my.  These clumsy semantics just can’t fit in my head.

> One way to test this would be to use setns (perhaps via
> container-excursion) to enter the namespaces of the builder, which
> will cause you to start out with a full set of effective capabilities
> in its user namespace, then try umount.  Or a test could be done
> within the daemon shortly prior to exec.

I tried running a build that sleeps and then joining its namespaces but
failed:

--8<---------------cut here---------------start------------->8---
$ pgrep -fa builder
16091 guile --no-auto-compile -L /home/ludo/src/guix/test-tmp/store/ngrj4gl9lrbmbklcsbgcrq622n9nf0jw-module-import -C /home/ludo/src/guix/test-tmp/store/cskis66zjnhk28h11lbaxkd3j9lyzz6a-module-import-compiled /home/ludo/src/guix/test-tmp/store/akndbdx1lmnigf8bi29dr0vd3c8dbdrg-attempt-to-unmount-input-builder
$ nsenter -m -u -i -n -p -U  -t 16091 
nsenter: reassociate to namespace 'ns/ipc' failed: Operation not permitted
$ guix container exec 16091 /bin/sh
guix container: error: setns: 7 0: Operation not permitted
guix container: error: process exited with status 1
--8<---------------cut here---------------end--------------->8---

If you can think of ways to do that, I’m all ears.  :-)

You can try from the ‘wip-rootless-daemon’ at
<https://codeberg.org/civodul/guix> and apply the patch I sent earlier.

(Incidentally, I don’t think we could write an automated test for that;
in theory we could use (guix scripts processes) to determine the PID of
the build process but that would be too brittle, especially when running
“make check -j123” where it could pick the wrong guix-daemon process.)

> Note that we still need to initialize /proc/self/uid_map and friends for
> the new user namespace, if I understand correctly.

Yes, I left that for later (it triggers a test failure anyway, so we
won’t forget.)

> My reading of user_namespaces(7) is that it should be possible to do
> this from within the new user namespace.

Oh, interesting.

> I hadn't heard of that restriction on unshare and clone.  Thinking about
> it, I suppose the reason could be that merely creating a user namespace
> grants CAP_SYS_CHROOT, and because the current root directory is a
> per-process property whose setting isn't limited by any namespace, it
> would be possible to undo a chroot someone had tried to set as a
> restriction on the current process by just calling chroot("/").  But if
> we use pivot_root in conjunction with it, like we do in the daemon, it
> should work.

Interesting.  Thanks for your guidance, as always!

Ludo’.