NixOS / nixpkgs

Nix Packages collection & NixOS
MIT License
18.05k stars 14.08k forks source link

SUID wrappers die when executed with NO_NEW_PRIVS #98863

Closed robryk closed 1 year ago

robryk commented 4 years ago

Describe the bug Wrappers for S[UG]ID binaries crash if they are executed in a way that doesn't cause escalation to happen (i.e. leaves effective UID unchanged), even though the binary has the S[UG]ID bit set.

To Reproduce Steps to reproduce the behavior:

$ mount | head # works
devtmpfs on /dev type devtmpfs (rw,nosuid,size=1645200k,nr_inodes=4102596,mode=755)
devpts on /dev/pts type devpts (rw,nosuid,noexec,relatime,gid=3,mode=620,ptmxmode=666)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
tmpfs on /run type tmpfs (rw,nosuid,nodev,size=8226000k,mode=755)
none on /run/keys type ramfs (rw,nosuid,nodev,relatime,mode=750)
tmpfs on /run/wrappers type tmpfs (rw,nodev,relatime)
sysfs on /sys type sysfs (rw,nosuid,nodev,noexec,relatime)
/dev/mapper/cryptroot on / type ext4 (rw,relatime)
/dev/mapper/cryptroot on /nix/store type ext4 (ro,relatime)
$ $(nix-build '<nixpkgs>' -A busybox)/bin/setpriv --nnp mount # doesn't work
mount: /nix/store/v6l2sacryfr88yqq0pq7sia8wfgm9q31-wrapper.c:203: main: Assertion `!(st.st_mode & S_ISUID) || (st.st_uid == geteuid())' failed.
Aborted

Expected behavior I expect SUID wrapper to simply run the underlying binary if something (NO_NEW_PRIVS, nosuid mountpoint, etc.) prevented the effective UID from changing.

Additional context I have initially encountered this issue while using bubblewrap (which sets NO_NEW_PRIVS on all the processes it starts in user namespaces), so it's not completely academic.

I think the correct way to detect if escalation happened is to check whether UID and EUID are equal -- if they are we can be sure that we weren't escalated using the S[UD]ID mechanism. Some more care might be required due to capabilities, though.

Notify maintainers @ixmatus -- the code of the dying wrappers is in nixos/modules/security/wrappers, and @ixmatus seems to have made most recent meaningful contributions there

Metadata

$ nix-shell -p nix-info --run "nix-info -m"
 - system: `"x86_64-linux"`
 - host os: `Linux 5.4.59, NixOS, 20.09pre239318.c59ea8b8a0e (Nightingale)`
 - multi-user?: `yes`
 - sandbox: `yes`
 - version: `nix-env (Nix) 2.3.7`
 - channels(root): `"nixos-20.09pre239318.c59ea8b8a0e"`
 - channels(robryk): `"home-manager-20.03"`
 - nixpkgs: `/nix/var/nix/profiles/per-user/root/channels/nixos`

Maintainer information:

# a list of nixpkgs attributes affected by the problem
attribute:
# a list of nixos modules affected by the problem
module:
robryk commented 4 years ago

Ah, a better way of checking whether any escalation occurred (if not, we can simply exec the underlying binary without much care) is to check whether AT_SECURE is set in the auxiliary vector (see getauxval(3)).

solson commented 4 years ago

I just got surprised by this while trying out bubblewrap for the first time. To confirm, it dies on the same assertion:

$ bwrap --dev-bind / / sudo echo foo
sudo: /nix/store/v6l2sacryfr88yqq0pq7sia8wfgm9q31-wrapper.c:203: main: Assertion `!(st.st_mode & S_ISUID) || (st.st_uid == geteuid())' failed.
stale[bot] commented 3 years ago

I marked this as stale due to inactivity. → More info

solson commented 3 years ago

The issue in my previous comment is still reproducible on nixpkgs master.