Replace sudo with doas

There are many miscellaneous improvements that could be done to vastly harden Whonix.

Let’s take the program sudo that is a SUID program and is written primarily with companies use-cases in mind. It supports complex configuration and the source-code is relatively Large and not properly audited. Think of the exploit that affected it for years and no one knew about it.

I chose to start the miscellaneous improvements thread with sudo since Whonix does not use any sudo complex configuration quirks and thus making the jump should be seamless with no major issues.

Switching to the more secure and audited alternative doas which is built with security and desktop usage in mind can bring enormous security benefits to Whonix.

You could even alias sudo='doas' to make the transition even more seamless.

I am willing to do the required extensive testing on my Whonix machine and report back any issues I may encounter.

2 Likes

sudo exploitability hysteria is old news. There are tons of articles about this, it’s perfectly suitable and safe.

1 Like

No hysteria involved in writing this post. I am talking purely about security, doas is simply a lot more secure. And don’t take my word for it, take the experts word who wrote, the same guys who work on OpenBSD.

Even in-house security experts such as @madaidan recommend doas over sudo

1 Like

Some quotations / references on sudo vs doas would help to settle the question if it is more secure.

doas seems also written in C. At least rust would have been nicer. Or if sudo (or doas) was mostly rewritten in python and only strictly necessary parts in rust that cannot be done with python. That said, before using doas, are there even more secure alternatives?

Did you grep the Kicksecure / Whonix source code yet to see if it is feasible to replace it?

2 Likes

Does doas support credential caching? dist-installer-cli (Kicksecure / Whonix - Linux installer) runs as user but uses sudo several times when required. If needing to re-enter the password several times that would be impractical.

2 Likes

Some quotations / references on sudo vs doas would help to settle the question if it is more secure.
references:

doas is a minimal replacement for the venerable sudo. It was initially written by Ted Unangst of the OpenBSD project to provide 95% of the features of sudo with a fraction of the codebase.

It is exactly same as sudo except much less codebase (reduced attack-surface) and is written with Desktop and security in mind, things that sudo lacks as it is written with companies in mind.

It is written by the same people who wrote openSSH, openBSD and more. It is vetted.

Does doas support credential caching?

doas does support credential caching with a simple configuration file such as this:
permit persist :wheel

2 Likes

https://salsa.debian.org/debian/opendoas#peristtimestamptimeout contradicts this.

Perist/Timestamp/Timeout

The persist feature is disabled by default and can be enabled with the configure flag --with-timestamp.

This feature is new and potentially dangerous, in the original doas, a kernel API is used to set and clear timeouts. This API is openbsd specific and no similar API is available on other operating systems.

As a workaround, the persist feature is implemented using timestamp files similar to sudo.

See the comment block in timestamp.c for an in-depth description on how timestamps are created and checked to be as safe as possible.

2 Likes

Apart from that the next step could be:

  • Check current uses of Kicksecure / Whonix source code using sudo. This could use a complete review. Attempt to replace these uses by using capabilities, if applicable. Maybe neither would be required.
  • Do the same for pkexec because if getting rid if sudo should get rid of pkexec too?
  • The /etc/sudoers.d configuration drop-in snippets probably don’t hurt and can remain even if sudo would be no longer installed by default.
  • If sane, feasible… Replace all users of sudo with root-wrapper (to be invented) (part of helper-scripts) a tool that uses doas if available, falls back to sudo if available or errors out if neither is available. This might help during migration and keep this flexible.
  • It seems there’s no /etc/doas.conf.d configuration snippet drop-in folder. Please post a feature request and/or contribute to upstream (if they were to accept such a feature).
  • Because without /etc/doas.conf.d how would each package configure the required exceptions?
2 Likes

That is odd. is important to keep in mind that there is 2 versions of opendoas, one for BSD systems and one for Linux systems.

2 Likes

So I decided it’s enough talking and it’s time to get straight to the action.

Time to remove sudo and install doas !

NOTE:: I am using KVM port of Whonix made by @HulaHoop

To reliably test, I am going to start by only replacing sudo from Workstation.

I first looked up doas package in bookworm, noticed it is a transitional package for [opendoas](https://packages.debian.org/bookworm/opendoas)

So I installed [opendoas](https://packages.debian.org/bookworm/opendoas)

OFF-TOPIC:: As it installed, apt told me there is a package called busybox which is installed and no longer needed, potentiality room for improvement here ? @HulaHoop consider removing busybox since we already have all gnu tools installed, makes no sense to have it really.
And would love if @patrick checked on Virtualbox to confirm / deny busybox package being installed by default

Back to topic:
I configure opendoas by first making a directory /etc/doas.d/ then inside I create doas.conf with the following content:

# This will allow users in the wheel group to use doas.
permit persist :wheel

Then I make a symlink in /etc/doas.conf

ln -s /etc/doas.d/doas.conf /etc/doas.conf

I then ran the command groups to show what groups I am apart of, and received the following:

user cdrom sudo audio dip plugdev users console ssh debian-tor

I was baffled at first why my user is not part of the wheel group but I guess whonix uses the sudo group instead? Is it a security risk to add myself to the wheel group and remove sudo from my user ?

Anyway I went back again and edited /etc/doas.conf to edit wheel to sudo

permit persist :sudo

For your information, persist means cache creditenels so you only have to type password once in a terminal, but if you close terminal and try in another one you must enter password again. Same exact behavior which is done by sudo.

Bam, it all works extremely well!

Now back to the big guns, before I remove the sudo package, I took a look at /etc/sudoers and /etc/sudoers.d/ files to confirm that Whonix does not use any kind of special configuration for it.
Turns out it does but I decided to go the reverse engineer way. I simply backed up the original sudoers files, then I wrote

doas apt remove sudo

Then I got the following:

The following packages will be REMOVED:
  anon-ws-disable-stacked-tor apparmor-profile-dist apparmor-profiles-kicksecure
  bootclockrandomization dist-base-files helper-scripts kicksecure-default-applications-cli
  kicksecure-dependencies-cli kicksecure-dependencies-system kicksecure-desktop-applications-xfce
  kicksecure-desktop-environment-essential-gui kicksecure-desktop-environment-essential-xfce
  kicksecure-recommended-cli legacy-dist msgcollector msgcollector-gui non-qubes-audio
  non-qubes-vm-enhancements-cli non-qubes-vm-enhancements-gui non-qubes-whonix-workstation-cli
  non-qubes-whonix-workstation-xfce open-link-confirmation repository-dist sdwdate sdwdate-gui
  security-misc setup-dist setup-wizard-dist sudo swap-file-creator systemcheck tb-default-browser
  tb-starter tb-updater usability-misc vm-config-dist whonix-base-files whonix-firewall
  whonix-shared-default-applications-gui whonix-shared-packages-dependencies-cli
  whonix-shared-packages-recommended-cli whonix-workstation-packages-dependencies-cli
  whonix-workstation-packages-dependencies-pre whonix-workstation-packages-recommended-cli
  whonix-workstation-packages-recommended-gui

I immediately did “N” to prevent everything from being removed , what’s up with that? why it pulled all these packages ?

2 Likes

links:

group wheel:

busybox:

Not sure what this is good for but this won’t abolish the need for native /etc/dosas.d support.

Because these packages Depends: on sudo. You see that if you analyze current uses of sudo by Searching the Source Code.

Without looking at the source code, no meaningful progress can be made here because there are many invocations of sudo --non-interactive (and pkexec).

2 Likes

I am cloning the kicksecure repo right now. Will grep through it.

2 Likes

Just bumping this, I’ve been using exclusively doas for years now and have been setting up my Whonix gateway. I encountered the same problem neo here has when removing sudo. Just wanted to throw in I’d be happy to help out and patch these programs with a doas case and test.

If you want to collaborate on this @neo0xff let me know and I can share my matrix

1 Like

We can collaborate through the forum but Matrix is fine too

1 Like

If you don’t like sudo, then you also don’t like pkexec?

pkexec presumably is even more fancy, complex. Yet, I didn’t find any other way to allow GUI applications take root actions such as:

  • Anon Conection Wizard (ACW) writing to Tor configuration, or
  • Derivative Repository Wizard writing /etc/apt/sources.list.d/derivative.list file,
  • etc.

Except for pkexec / sudo.

2 Likes

Problem with pkexec is that it breaks hidepid.

2 Likes

Yes, yes I do not fancy the idea of running GUI stuff on root.

I am not expert on the matter but on Linux, virt-manager somehow manages to manage VMs that are only accessible to root user while virt-manager it’s self is running as user, I think it has something to do with polkit. Maybe we should look into that?

1 Like

So, I ended up researching this because of issues I ran into with sudo and PAM (details available at pam_faillock tally and lockout status is reset by running a command with a NOPASSWD exception using sudo · Issue #842 · linux-pam/linux-pam · GitHub and NOPASSD exceptions in `/etc/sudoers(.d)` interact poorly with `pam_faillock`, no configuration option available to allow sudo to tell PAM when a NOPASSWD command is being run · Issue #415 · sudo-project/sudo · GitHub for those who are interested). This is what I’ve come up with so far from my research and from discussion with @Patrick elsewhere:

  • For /etc/doas.conf.d support, Patrick’s idea was that this could be provided without modifying doas upstream, for instance by creating a build script that would build all files under /etc/doas.conf.d into a single /etc/doas.conf file. Something very simple like this might work:
readarray -t doas_d_list < <(find /etc/doas.conf.d -mindepth 1 -maxdepth 1)
safe_rm /etc/doas.conf
for doas_d_file in "${doas_d_list[@]}"; do
   cat "${doas_d_file}" | tee -a -- '/etc/doas.conf'
done
  • doas works around the sudo issues mentioned in the above bug reports. It looks like this is because it doesn’t go through PAM at all when a nopass rule is matched, though I’m not 100% certain this is what’s happening.
  • permission-hardener is stripping the setuid bit from /usr/bin/doas, can be put back with sudo chmod 4755 /usr/bin/doas, an exception will be needed for it in order for this to work.
  • I looked at all places where Kicksecure and Whonix use sudoers config (cd ~/derivative-maker/packages; find | grep sudoers), then compared the existing configuration with doas’s feature set documented at doas.conf(5) - OpenBSD manual pages. Here’s the list of what looks like it can be ported and what looks like it may have problems. A checkmark means “looks like it can be ported” or “isn’t necessary”, no checkmark means it’s likely to be problematic.

kicksecure/desktop-config-dist/etc/sudoers.d/desktop-config-dist

  • Should be translatable to doas. nopasswd exceptions for specific commands with specific argument sets, for specific users and groups.
    • %sudo ALL=NOPASSWD: /bin/lsblk --noheadings --raw --output RO
    • translates to:
    • permit nopass :sudo cmd /bin/lsblk args --noheadings --raw --output RO

kicksecure/dist-base-files/etc/sudoers.d/30_default-password-lecture

  • doas doesn’t have a lecture, so this can just be removed/ignored.

kicksecure/live-config-dist/etc/sudoers.d/live-config-dist

  • More commands with nopasswd exceptions.

kicksecure/msgcollector/etc/sudoers.d/msgcollector

  • This one’s slightly trickier, it allows certain environment variables to be preserved for a set of commands. With sudo, we’re using Defaults:ALL env_keep += "var" syntax, but doas only supports environment variable exceptions on a per-command basis. However, it does allow doing this on a per-command basis, so this is workable. (EDIT: actually you can specify environment variable exceptions that have a very wide reach!)
    • Defaults:ALL env_keep += "msgdisptacher_username"
    • %sudo ALL=NOPASSWD: /usr/libexec/msgcollector/msgdispatcher_delete_wrapper
    • translates to:
    • permit nopass keepenv setenv { msgdispatcher_username } :sudo cmd /usr/libexec/msgcollector/msgdispatcher_delete_wrapper (command-specific environment variable exception, can be adjusted to make the environment variable exception more widely applicable)
    • Note that this syntax allows arbitrary arguments to be passed to the command listed after cmd, blocking this requires addingan args parameter that specifies no further arguments. The sudo command shown doesn’t block arbitrary arguments either though so this should be an accurate translation.

kicksecure/sdwdate/etc/sudoers.d/sdwdate

  • This one’s a problem. Whereas the previous files provide nopasswd exceptions to specific users and groups, this file allows anyone to run /usr/sbin/sdwdate-clock-jump as root. doas lacks the ability to express a universal exception such as this, you can only grant exceptions to specific users or groups. The only files that actually attempt to use sdwdate-clock-jump via sudo are:
  • kicksecure/sdwdate-gui/usr/lib/python3/dist-packages/sdwdate_gui/sdwdate_gui.py
  • kicksecure/sdwdate-gui/usr/lib/python3/dist-packages/sdwdate_gui/sdwdate_gui_qubes.py
  • kicksecure/sdwdate-gui/etc/qubes-rpc/whonix.GatewayCommand
  • It’s likely that all of these can be coped with by using doas’s configuration by simply determining the users or groups these run as, and adding them to the configuration file. Adding the users group to the config would also be advisable as Debian’s adduser tool will automatically add new “standard” user accounts to this group. Unfortunately useradd doesn’t do this, but the end-user can probably resolve this themselves if they so choose.
    • ALL ALL=NOPASSWD: /usr/sbin/sdwdate-clock-jump
    • translates roughly to
    • permit nopass :users cmd /usr/sbin/sdwdate-clock-jump

kicksecure/sdwdate-gui/etc/sudoers.d/sdwdate-gui

  • User-specific nopasswd exceptions for specific commands. Easy to translate.

kicksecure/security-misc/etc/sudoers.d/pkexec-security-misc

  • The file is entirely commented out, however both of the commented-out commands should be translatable. One is a group-specific nopasswd exception, which as we’ve covered already is translatable. The other one adds PKEXEC_UID to the list of env_keep variables, which again would have to be handled on a command-by-command basis. The command that needs the sudoers configuration is xfpm-power-backlight-helper, thus assuming the user account running this is user and this should work without a password:
    • Defaults:ALL env_keep += "PKEXEC_UID"
    • translates roughly to
    • permit nopass keepenv setenv { PKEXEC_UID } user cmd /usr/sbin/xfpm-power-backlight-helper

kicksecure/security-misc/etc/sudoers.d/security-misc

  • One user-specific and one group-specific nopasswd exception, easily translatable.

kicksecure/security-misc/etc/sudoers.d/xfce-security-misc

  • Entirely commented out, but if we do need the commands here, there’s trouble. These are group-specific nopasswd exceptions, but some of the command line arguments to the xfpm-power-backlight-helper application are being validated with regex matching, matching a number between 1 and 3 digits long (probably between 0 and 100 I would guess), doas does not support regex matching. This could theoretically be hacked around by using a tempfile rather than command-line arguments for input, but that requires modding XFCE most likely, which isn’t going to happen I don’t think. Alternatively, 100 or so configuration lines could be used to match every possible option here, but that would be horrible.
    • %sudo ALL=NOPASSWD: /usr/sbin/xfpm-power-backlight-helper --set-brightness [[\:digit\:]]
    • translates roughly to
    • permit nopass :sudo cmd /usr/sbin/xfpm-power-backlight-helper args --set-brightness 1 and so on

kicksecure/setup-dist/etc/sudoers.d/setup-dist

  • Simple group-specific nopasswd exception, easily translatable.

kicksecure/setup-wizard-dist/etc/sudoers.d/setup-wizard-dist

  • Contains no commands, can be translated by omission.

kicksecure/systemcheck/etc/sudoers.d/systemcheck

  • Complex, but looks doable. Many user-specific nopasswd exceptions, however some of these are targeted to allow the user to execute a command as another user other than root. Thankfully doas supports this.
    • user ALL=(sdwdate) NOPASSWD: /usr/libexec/helper-scripts/onion-time-pre-script
    • translates to
    • permit nopass user as sdwdate cmd /usr/libexec/helper-scripts/onion-time-pre-script

kicksecure/tb-starter/etc/sudoers.d/tb-starter

  • A user-specific nopasswd exception with some environment variable allowances. Can be handled using techniques mentioned earlier.

kicksecure/tb-updater/etc/sudoers.d/tpo-downloader

  • More user- and group-specific nopasswd exceptions. Easily translatable.

`kicksecure/tor-control-panel/etc/sudoers.d/restart-tor-gui

  • Contains no commands, can be translated by omission.

kicksecure/tor-control-panel/etc/sudoers.d/tor-control-panel

  • Contains no commands, can be translated by omission.

kicksecure/usability-misc/etc/sudoers.d/pwfeedback

  • doas has no pwfeedback switch, and it doesn’t display asterisks as the user types their password, so this would sadly be lost in a migration.

kicksecure/usability-misc/etc/sudoers.d/sudo-lecture-disable

  • More lecture-related stuff. doas has no lecture, thus this can be translated by omission.

kicksecure/usability-misc/etc/sudoers.d/tunnel_unpriv

  • Mostly translatable, user-specific nopasswd exceptions with environment variable allowances. There are two worrying lines though:
  • Defaults:tunnel !requiretty - as I understand it, this allows the tunnel user to run commands even without being logged in at a TTY. doas allows users to do this (and there’s no way to tell it to not allow that), so this doesn’t need translated.
  • ALL=(ALL) NOPASSWD: /usr/sbin/openvpn *. This looks like it allows running openvpn with any arguments? In that instance why is the * present? Assuming the * is superfluous, this is translatable, but if it’s meant to mean “match any one argument, but only one argument”, then this isn’t translatable and any desirable arguments would have to be listed, each on its own config line.

kicksecure/usability-misc/etc/sudoers.d/upgrade-passwordless

  • Group-specific nopasswd exception, easily translatable.

kicksecure/usability-misc/etc/sudoers.d/user-passwordless

  • Entirely commented out, grants all members of group sudo passwordless sudo privileges for everything. Easily translatable.
    • sudo ALL=(ALL:ALL) NOPASSWD:ALL`
    • translates to
    • permit nopass :sudo

whonix/anon-gw-anonymizer-config/etc/sudoers.d/anonymizer-config-gateway

  • More user-specific nopasswd exceptions. Easily translatable.

whonix/uwt/etc/sudoers.d/uwt

  • Environment variable whitelisting to work around a torsocks issue. Due to doas’s design, this isn’t translatable, environment variable whitelists have to be attached to specific commands. There isn’t any clear exception for torsocks in the sudoers config, so this may require some redesigning to work around. Almost easily translatable, the “applies to all users” bit won’t carry over, but otherwise it isn’t a problem. (On top of this, I don’t think this environment variable is even needed anymore.)
    • Defaults:ALL env_keep += "TORSOCKS_LOG_LEVEL"
    • translates roughly to:
    • permit setenv { TORSOCKS_LOG_LEVEL } :users

All in all, it looks like a migration to doas is potentially within reach. There’s a lot that has to be changed and tested for this to work, so this could take a month or even more were this to be something Kicksecure and Whonix wanted to pursue.

2 Likes

This is also a good opportunity to harden all /etc/sudoers.d exceptions.

Plan:

  1. harden all /etc/sudoers.d exceptions
  2. keep the /etc/sudoers.d for now even should we decide to no longer install sudo by default (to make it easier to go back to sudo, should a blocker come up)
  3. implement /etc/doas.conf configuration generator in security-misc
  4. add the /etc/doas.conf.d snippets
  5. maybe port to doas

You did an amazing analysis of Kicksecure, Whonix /etc/sudoers.d snippets!

Could you please also investigate the already existing /etc/sudoers.d exceptions shipped by other projects such as Qubes? Because these will also need to be considered before we can port to doas.

sudo ls -la /etc/sudoers.d

The configuration generator would need to be atomic. Generate a variable first, then write with 1 command in a atomic way using sponge.

Also the configuration generator should not overwrite a maybe already existing user generated configuration. One that lacks our auto generated comment.

No problem. Hardened just now in git.

Deleted.

Deleted.

Not a blocker. All commented out by default. Not a priority. If a user urgently needs this and it’s not possible with doas, the user could install sudo.

2 Likes

Deleted.

(After refactoring / re-designing msgcollector, a sudoers.d exception is no longer required.)

2 Likes