unofficial mirror of bug-guix@gnu.org 
 help / color / mirror / code / Atom feed
From: Nathan Nye <nnye@whitebeamsec.com>
To: 47229@debbugs.gnu.org
Subject: bug#47229: Hardlink mitigation limits
Date: Tue, 23 Mar 2021 14:18:14 -0400	[thread overview]
Message-ID: <8f95179a-5574-98bd-c44e-f5ee74638dc3@whitebeamsec.com> (raw)
In-Reply-To: <aa062a0d-071c-f015-983e-492cf5cee9d8@whitebeamsec.com>

[-- Attachment #1: Type: text/plain, Size: 3137 bytes --]

Hello,

I'm sharing here for future reference why protected hardlinks alone did 
not mitigate the recent LPE security advisory, pre-patch:

"The reasons why are lines 2633 and 2637 of nix/libstore/build.cc:

  * https://git.savannah.gnu.org/cgit/guix.git/tree/nix/libstore/build.cc#n2633
  * https://git.savannah.gnu.org/cgit/guix.git/tree/nix/libstore/build.cc#n2637

When a package fails to build and the keep failed flag is set 
(-K/--keep-failed), it runs a recursive chown on the build directory 
(which is writable following guixbuilder01 changing the permissions to 
777). It starts at the top level and chowns downwards.

The first important thing to notice here is that at any point (even 
pre-chown) the build user has been compromised. The build user can write 
a SUID /bin/sh to the build path, and because a normal user can traverse 
into the directory before and during the chown, they can run a SUID 
shell (allowing them to become guixbuilder01 even after the build user 
processes are terminated). Becoming the build user allows multiple paths 
to privilege escalation, but in this scenario we have faster ways of 
becoming root.

Moving on to getting root, we're choosing not to use a hardlink to show 
why it isn't necessary. Instead, we create a directory under the build 
directory with thousands of sequentially named files, the final entry 
being "passwd" or "shadow". Then we terminate the build and watch for 
the first entry to be chowned to our user ID (possibly with the inotify 
API). This way, we have opened a lengthy window of time where it is 
enumerating over a list of file paths in our chosen directory and 
chowning each of them. Now we can execute our TOCTOU race condition 
vulnerability.

At the time of check (TOC), the guix-daemon has a list of file paths to 
chown under what it assumes is a regular directory (because it ran 
S_ISDIR on the directory). But we can swap out the directory from under 
it with a symlink to /etc (most efficiently with renameat2() and using 
the RENAME_EXCHANGE flag to atomically exchange the paths). At the time 
of use (TOU) lchown() only checks if the file /itself/ that is being 
chowned is a symlink, not if the path components are, as can be 
demonstrated with Python:

$ mkdir td;touch td/tf;python3 -c 'import os;os.lchown("/home/example/td/tf", 1000, 4)';ls -lahtrd td td/tf
-rw-rw-r-- 1 example adm       0    Mar 19 19:20 td/tf
drwxrwxr-x 2 example example   4.0K Mar 19 19:20 td
$ rm -rf td
$ mkdir td; ln -s td td2;touch td2/tf;python3 -c 'import os;os.lchown("/home/example/td2/tf", 1000, 4)';ls -lahtrd td2 td2/tf
lrwxrwxrwx 1 example example 2 Mar 19 19:21 td2 -> td
-rw-rw-r-- 1 example adm     0 Mar 19 19:21 td2/tf

So lchown can blindly chown /etc/passwd to our user by following the 
directory symlink and subsequently verifying that passwd itself is not a 
symlink. I hope this explains the TOCTOU race condition and why 
protected hardlinks help (forcing an attacker to get root using this 
race condition), but they are not a solution to the problem (alone)."

- Nathan


[-- Attachment #2: Type: text/html, Size: 4095 bytes --]

       reply	other threads:[~2021-03-23 20:29 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <aa062a0d-071c-f015-983e-492cf5cee9d8@whitebeamsec.com>
2021-03-23 18:18 ` Nathan Nye [this message]
2021-03-29 15:22   ` bug#47229: Hardlink mitigation limits Ludovic Courtès

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://guix.gnu.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8f95179a-5574-98bd-c44e-f5ee74638dc3@whitebeamsec.com \
    --to=nnye@whitebeamsec.com \
    --cc=47229@debbugs.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/guix.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).