A security issue has been identified inguix-daemonwhich allows for a local user to gain the privileges of any of the build usersand subsequently use this to manipulate the output of any build. Youare strongly advised to upgrade your daemon now (see instructionsbelow), especially on multi-user systems.

This exploit requires the ability to start a derivation build and the ability torun arbitrary code with access to the store in the root PID namespace on themachine the build occurs on. As such, this represents an increased riskprimarily to multi-user systems and systems using dedicated privilege-separationusers for various daemons: without special sandboxing measures, any process oftheirs can take advantage of this vulnerability.

VulnerabilityFor a very long time, guix-daemon has helpfully made the outputs of failedderivation buildsavailableat the same location they were at in the build container. This has aided greatlyespecially in situations where test suites require the package to already beinstalled in order to run, as it allows one to re-run the test suiteinteractively outside of the container when built with --keep-failed. Thistransferral of store items from inside the chroot to the real store wasimplemented with a simple rename, and no modification of the store item orany files it may contain.

If an attacker starts a build of a derivation that creates a binary with thesetuid and/or setgid bit in an output directory, then, and the build fails, thatbinary will be accessible unaltered for anybody on the system. The attacker or acooperating user can then execute the binary, gain the privileges, and fromthere use a combination of signals and procfs to freeze a builder, open any fileit has open via /proc/$PID/fd, and overwrite it with whatever it wants. Thismanipulation of builds can happen regardless of which user started the build, soit can work not only for producing compromised outputs for commonly-usedprograms before anybody else uses them, but also for compromising any buildsanother user happens to start.

A related vulnerability was also discovered concerning the outputs ofsuccessful builds. These weremoved -also via rename() - outside of the container prior to having theirpermissions, ownership, and timestampscanonicalized. Thismeans that there also exists a window of time for a successful build's outputsduring which a setuid/setgid binary can be executed.

In general, any time that a build user running a build for some submitter canget a setuid/setgid binary to a place the submitter can execute it, it ispossible for the submitter to use it to take over the build user. This situationalways occurs when --disable-chroot is passed to guix-daemon. This holdseven in the case where there are no dedicated build users, and builds happenunder the same user the daemon runs as, as happens during make check in theguix repository. Consequently, if a permissive umask that allows executepermission for untrusted users on directories all the way to a user's guixcheckout is used, an attacker can use that user's test-environment daemon togain control over their user while make check is running.

MitigationThis security issue has been fixed bytwocommits. Usersshould make sure they have updated to the second commit to be protected fromthis vulnerability. Upgrade instructions are in the following section. If thereis a possibility that a failed build has left a setuid/setgid binary lyingaround in the store by accident, run guix gc to remove all failed buildoutputs.

The fix was accomplished by sanitizing the permissions of all files in a failedbuild output prior to moving it to the store, and also by waiting to movesuccessful build outputs to the store until after their permissions had beencanonicalized. The sanitizing was done in such a way as to preserve as manynon-security-critical properties of failed build outputs as possible to aid indebugging. After applying these two commits, the guix package in Guix wasupdatedso that guix-daemon deployed using it would use the fixed version.

If you are using --disable-chroot, whether with dedicated build users or not,make sure that access to your daemon's socket is restricted to trustedusers. This particularly affects anyone running make check and anyone runningon GNU/Hurd. The former should either manually remove execute permission foruntrusted users on their guix checkout or apply thispatch, which restricts access to thetest-environment daemon to the user running the tests. The latter should adjustthe ownership and permissions of /var/guix/daemon-socket, which can be donefor Guix System users using the new socket-directory-{perms,group,user} fieldsin this patch.

A proof of concept is available at the end of this post. One can run this codewith:

guix repl -- setuid-exposure-vuln-check.scm This will output whether the current guix-daemon being used is vulnerable ornot. If it is not vulnerable, the last line will contain your system is not vulnerable, otherwise the last line will contain YOUR SYSTEM IS VULNERABLE.

UpgradingDue to the severity of this security advisory, we strongly recommendall users to upgrade their guix-daemon immediately.

For Guix System, theprocedureis to reconfigure the system after a guix pull, either restartingguix-daemon or rebooting. For example:

guix pullsudo guix system reconfigure /run/current-system/configuration.scmsudo herd restart guix-daemon where /run/current-system/configuration.scm is the current systemconfiguration but could, of course, be replaced by a systemconfiguration file of a user's choice.

For Guix running as a package manager on other distributions, oneneeds to guix pull with sudo, as the guix-daemon runs as root,and restart the guix-daemon service, asdocumented.For example, on a system using systemd to manage services, run:

sudo --login guix pullsudo systemctl restart guix-daemon.service Note that for users with their distro's package of Guix (as opposed tohaving used the installscript)you may need to take other steps or upgrade the Guix package as perother packages on your distro. Please consult the relevantdocumentation from your distro or contact the package maintainer foradditional information or questions.

ConclusionEven with the sandboxing features of modern kernels, it can be quite challengingto synthesize a situation in which two users on the same system who aredetermined to cooperate nevertheless cannot. Guix has an especially difficultjob because it needs to not only realize such a situation, but also maintain theability to interact with both users itself, while not allowing them to cooperatethrough itself in unintended ways. Keeping failed build outputs around fordebugging introduced a vulnerability, but finding that vulnerability because ofit enabled the discovery of an additional vulnerability that would have existedanyway, and prompted the use of mechanisms for securing access to the guixdaemon.

I would like to thank Ludovic Courtès for giving feedback on thesevulnerabilities and their fixes — discussion of which led to discovering thevulnerable time window with successful build outputs — and also for helping meto discover that my email server was broken.

Proof of ConceptBelow is code to check if your guix-daemon is vulnerable to this exploit. Savethis file as setuid-exposure-vuln-check.scm and run following the instructionsabove, in "Mitigation."

(use-modules (guix) (srfi srfi-34))(define maybe-setuid-file ;; Attempt to create a setuid file in the store, with one of the build ;; users as its owner. (computed-file "maybe-setuid-file" #~(begin (call-with-output-file #$output (const #t)) (chmod #$output #o6000) ;; Failing causes guix-daemon to copy the output from ;; its temporary location back to the store. (exit 1))))(with-store store (let* ((drv (run-with-store store (lower-object maybe-setuid-file))) (out (derivation->output-path drv))) (guard (c (#t (if (zero? (logand #o6000 (stat:perms (stat out)))) (format #t "~a is not setuid: your system is not \vulnerable.~%" out) (format #t "~a is setuid: YOUR SYSTEM IS VULNERABLE.Run 'guix gc' to remove that file and upgrade.~%" out)))) (build-things store (list (derivation-file-name drv))))))