Replace sudo with doas

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