SUID Disabler and Permission Hardener

I want to add a usability feature.

As user user.

stat -c "%n %a %U %G" /bin/su
/bin/su 755 root root
which su

/bin/su

I.e. su is still executable by user user even though it has suid removed. This is bad because su fails open, i.e. in weird ways. It does not report “missing suid”. What I preferred:

sudo chmod o-x /bin/su
stat -c "%n %a %U %G" /bin/su

/bin/su 754 root root

which su
su

bash: /bin/su: Permission denied

Now user user cannot execute su anymore. It is failing closed.

1 Like

This is the script output as of now.

run: dpkg-statoverride --add --update root root 0755 /home
run: dpkg-statoverride --add --update user user 0700 /home/user
run: dpkg-statoverride --add --update root root 0700 /root
run: dpkg-statoverride --add --update root root 0700 /boot
run: dpkg-statoverride --add --update root root 0600 /etc/permission-hardening.d
INFO: fso: ‘/usr/local/etc/permission-hardening.d’ - does not exist. This is likely normal.
INFO: set-user-id found - file_name: ‘/bin/fusermount’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /bin/fusermount
INFO: set-user-id found - file_name: ‘/bin/su’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /bin/su
INFO: set-user-id found - file_name: ‘/bin/ntfs-3g’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /bin/ntfs-3g
INFO: set-user-id found - file_name: ‘/usr/bin/sudo’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/bin/sudo
INFO: set-user-id found - file_name: ‘/usr/bin/chsh’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/bin/chsh
INFO: set-group-id found - file_name: ‘/usr/bin/crontab’ | existing_mode: ‘2755’ | new_mode: ‘755’
run: dpkg-statoverride --remove /usr/bin/crontab
run: dpkg-statoverride --add --update root crontab 755 /usr/bin/crontab
INFO: set-user-id found - file_name: ‘/usr/bin/chfn’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/bin/chfn
INFO: set-group-id found - file_name: ‘/usr/bin/ssh-agent’ | existing_mode: ‘2755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root ssh 755 /usr/bin/ssh-agent
INFO: set-user-id found - file_name: ‘/usr/bin/newuidmap’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/bin/newuidmap
INFO: set-user-id found - file_name: ‘/usr/bin/pkexec.security-misc-orig’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/bin/pkexec.security-misc-orig
INFO: set-user-id found - file_name: ‘/usr/bin/bwrap’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/bin/bwrap
INFO: set-group-id found - file_name: ‘/usr/bin/chage’ | existing_mode: ‘2755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root shadow 755 /usr/bin/chage
INFO: fso: ‘/usr/local/bin/’ - does not exist. This is likely normal.
INFO: set-user-id found - file_name: ‘/sbin/mount.nfs’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /sbin/mount.nfs
INFO: fso: ‘/usr/local/sbin/’ - does not exist. This is likely normal.
INFO: set-user-id found - file_name: ‘/usr/lib/policykit-1/polkit-agent-helper-1’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/policykit-1/polkit-agent-helper-1
INFO: set-user-id found - file_name: ‘/usr/lib/eject/dmcrypt-get-device’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/eject/dmcrypt-get-device
INFO: set-user-id set-group-id found - file_name: ‘/usr/lib/virtualbox/VBoxNetDHCP’ | existing_mode: ‘6755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/virtualbox/VBoxNetDHCP
INFO: set-user-id set-group-id found - file_name: ‘/usr/lib/virtualbox/VBoxNetNAT’ | existing_mode: ‘6755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/virtualbox/VBoxNetNAT
INFO: set-user-id set-group-id found - file_name: ‘/usr/lib/virtualbox/VBoxHeadless’ | existing_mode: ‘6755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/virtualbox/VBoxHeadless
INFO: set-user-id found - file_name: ‘/usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
INFO: set-user-id found - file_name: ‘/usr/lib/dbus-1.0/dbus-daemon-launch-helper’ | existing_mode: ‘4754’ | new_mode: ‘754’
run: dpkg-statoverride --remove /usr/lib/dbus-1.0/dbus-daemon-launch-helper
run: dpkg-statoverride --add --update root messagebus 754 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
INFO: set-user-id found - file_name: ‘/usr/lib/kde4/libexec/fileshareset’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/kde4/libexec/fileshareset
INFO: set-group-id found - file_name: ‘/usr/lib/kde4/libexec/kdesud’ | existing_mode: ‘2755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root nogroup 755 /usr/lib/kde4/libexec/kdesud
INFO: set-user-id found - file_name: ‘/usr/lib/chromium/chrome-sandbox’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/chromium/chrome-sandbox
INFO: set-user-id found - file_name: ‘/usr/lib/qubes/qfile-unpacker’ | existing_mode: ‘4755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root root 755 /usr/lib/qubes/qfile-unpacker
INFO: set-group-id found - file_name: ‘/usr/lib/evolution/camel-lock-helper-1.2’ | existing_mode: ‘2755’ | new_mode: ‘755’
run: dpkg-statoverride --add --update root mail 755 /usr/lib/evolution/camel-lock-helper-1.2
INFO: fso: ‘/usr/lib64/’ - does not exist. This is likely normal.
INFO: fso: ‘/usr/local/lib/’ - does not exist. This is likely normal.
INFO: fso: ‘/usr/local/lib32/’ - does not exist. This is likely normal.
INFO: fso: ‘/usr/local/lib64/’ - does not exist. This is likely normal.
run: dpkg-statoverride --add --update root root 4755 /usr/bin/sudo
run: dpkg-statoverride --add --update root root 4755 /usr/bin/bwrap
run: dpkg-statoverride --add --update root root 4755 /usr/lib/policykit-1/polkit-agent-helper-1
INFO: fso: ‘/usr/lib/spice-gtk/spice-client-glib-usb-acl-helper’ - does not exist. This is likely normal.
run: dpkg-statoverride --add --update root utmp 2755 /usr/lib/x86_64-linux-gnu/utempter/utempter

new_mode is either 755 or 754. I.e. has still execution permission for others or group.

For config entries stating nosuid only: Would it be a good idea to hardcode / change newmode of these to 744? I.e. to remove exeution permission for others and `group?

  if [ "$new_mode" = "755" ]; then
    new_mode=744
  fi
  if [ "$new_mode" = "754" ]; then
    new_mode=744
  fi
  if [ "$new_mode" = "745" ]; then
    new_mode=744
  fi

I guess the question is:

Are there suid or guid binaries which are still useful if suid / guid has been removed from these?

1 Like

Could you please review if it is sane to remove suid / guid from the following binaries? @madaidan

run: dpkg-statoverride --add --update root root 755 /bin/fusermount
run: dpkg-statoverride --add --update root root 755 /bin/su
run: dpkg-statoverride --add --update root root 755 /bin/ntfs-3g
run: dpkg-statoverride --add --update root root 755 /usr/bin/sudo
run: dpkg-statoverride --add --update root root 755 /usr/bin/chsh
run: dpkg-statoverride --remove /usr/bin/crontab
run: dpkg-statoverride --add --update root crontab 755 /usr/bin/crontab
run: dpkg-statoverride --add --update root root 755 /usr/bin/chfn
run: dpkg-statoverride --add --update root ssh 755 /usr/bin/ssh-agent
run: dpkg-statoverride --add --update root root 755 /usr/bin/newuidmap
run: dpkg-statoverride --add --update root root 755 /usr/bin/pkexec.security-misc-orig
run: dpkg-statoverride --add --update root shadow 755 /usr/bin/chage
run: dpkg-statoverride --add --update root root 755 /sbin/mount.nfs
run: dpkg-statoverride --add --update root root 755 /usr/lib/policykit-1/polkit-agent-helper-1
run: dpkg-statoverride --add --update root root 755 /usr/lib/eject/dmcrypt-get-device
run: dpkg-statoverride --add --update root root 755 /usr/lib/virtualbox/VBoxNetDHCP
run: dpkg-statoverride --add --update root root 755 /usr/lib/virtualbox/VBoxNetNAT
run: dpkg-statoverride --add --update root root 755 /usr/lib/virtualbox/VBoxHeadless
run: dpkg-statoverride --add --update root root 755 /usr/lib/x86_64-linux-gnu/lxc/lxc-user-nic
run: dpkg-statoverride --add --update root messagebus 754 /usr/lib/dbus-1.0/dbus-daemon-launch-helper
run: dpkg-statoverride --add --update root root 755 /usr/lib/kde4/libexec/fileshareset
run: dpkg-statoverride --add --update root nogroup 755 /usr/lib/kde4/libexec/kdesud
run: dpkg-statoverride --add --update root root 755 /usr/lib/chromium/chrome-sandbox
run: dpkg-statoverride --add --update root root 755 /usr/lib/qubes/qfile-unpacker
run: dpkg-statoverride --add --update root mail 755 /usr/lib/evolution/camel-lock-helper-1.2
run: dpkg-statoverride --add --update root root 4755 /usr/lib/policykit-1/polkit-agent-helper-1
run: dpkg-statoverride --add --update root utmp 2755 /usr/lib/x86_64-linux-gnu/utempter/utempter

Does the suid default whitelist need to be expanded?
Specifically, let’s not break chromium and virtualbox.

1 Like

Found some issue.

Dec 20 07:54:47 disp3633 permission-hardening[26043]: + seq -w 000 4777
Dec 20 07:54:47 disp3633 permission-hardening[26043]: + grep -qw 2755
Dec 20 07:54:47 disp3633 permission-hardening[26043]: seq: write error: Broken pipe

Need to use a better regex here.

Another issue.

user@disp3633:~$ sudoedit /usr/lib/security-misc/permission-hardening
sudoedit: /usr/bin/sudoedit must be owned by uid 0 and have the setuid bit set
user@disp3633:~$ sudo test
sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set

That is because there is a significant time gap between suid removal from /usr/bin and re-adding the whitelist of /usr/bin/sudo. Therefore we need to implement the whitelist another way. Not by first removing suid and then re-adding. Better to not modify file permissions of sudo (and other white listed ones) at all. Otherwise this can cause a lot bugs which are timing dependent (when other scripts use sudo).

1 Like

Not perfect but functional.

1 Like

Now also fixed:

1 Like

That does not work. It will “forget” to process some files.

find /usr/bin | wc -l

1149

Added a counter.

INFO: fso_to_process: ‘/usr/bin/’ | counter: ‘575’

1 Like

Fixed.

1 Like
sudo /usr/lib/security-misc/permission-hardening 

sudo: /usr/bin/sudo must be owned by uid 0 and have the setuid bit set

On Qubes there is also /bin/sudo and /bin/brwap. Fixed.

1 Like

Found a way to crazy speed up things. Using find with -perm /u=s,g=s. Will add.

1 Like

It’s fine. Do what you want. You’re better than me at writing bash scripts anyway.

You can just add another rule for su:

/bin/su 0700 root root

What’s the point of reading binaries if it can’t even be executed? Maybe just give a mode of 700.

It’s fine to remove it from most of them but whitelist sudo, virtualbox, polkit, dbus and chromium. Chromium only needs suid if unprivileged user namespaces are disabled which Debian does by default.

1 Like

Btw, I noticed in the script you refer to setgid as “guid”. It’s not “guid” but “sgid”. GUID is different and may cause confusion.

1 Like

VirtualBox has “plenty”. 6 at the moment.

In future, more/less might be added or paths might change. In that case, I would like to avoid hunting down bugs due to that.

Any reason not to add a nosuid whitelist matching feature? Could match for /virtualbox/.

I don’t see how such a matching feature could be abused. Threat model:
Any suid / sgid can only be abused by non-root as root does no longer need to escalate to root. Only only root (apt) and superroot can write to these folders anyhow. Therefore I see now way to create binaries which would match such names to gain access to a suid / sgid to be spared from suid removal. Well, there are ways, but those capable to to write to these folders do not need to bother with suid / sgid anymore.

Fixed in git master.

1 Like

Are any of these actually used? Is there any breakage from removing their SUID bits? If not, then we can just ignore them.

I doubt VboxNetDHCP would be used seeing as Whonix doesn’t even use DHCP at all.

Would be better to match for /usr/lib/virtualbox/ in case some random directory that just happens to have the name “virtualbox” gets whitelisted.

1 Like

set-user-id set-group-id found - file_name: ‘/usr/lib/xorg/Xorg.wrap’

Needed?

At first sight looks important. But Debian / systemd might not use / need it.

Not yet tested. Can’t find anything online what these are used for. Testing this can be future work.

security-misc isn’t just used by Whonix. I don’t want to break VirtualBox (hosts) for those who install security-misc or Kicksecure.

Will add.

1 Like

No, Debian and many other linux distros use Xorg rootless by default so there’s no need for the suid wrapper unless the user themselves has configured X to run as root for whatever reason (which is a security risk due to X’s large attack surface).

1 Like

We can use this to remove capabilities of some unneeded binaries too by using the none capability rule.

getcap -r / 2>/dev/null

/usr/lib/x86_64-linux-gnu/gstreamer1.0/grstreamer-1.0/gst-ptp-helper = cap_net_bind_service,cap_net_admin+ep
/bin/ping = cap_net_raw+ep

I think we should remove the capabilities of /bin/ping since it doesn’t work with Tor anyway.

1 Like

We can add Whonix specific things such as ping capability removal to anon-apps-config package as a drop- snippet.

Pull requests welcome.

1 Like
1 Like

This is now in the developers repository. Enabling it will be easy.

sudo systemctl enable permission-hardening.service

It might be enabled by default one day (similar to Restrict Hardware Information to Root - Testers Wanted!) but it needs a fair amount of testing as I am running into many issues here.

We’ll also need some way to record changes and to undo these.


Breaks whonix-firewall.

Dec 21 06:43:54 host enable-firewall[351]: iptables/1.8.2 Failed to initialize nft: Protocol not supported

1 Like