Deleted.
OK, so to begin with, I was wrong about doas only allowing environment variables to be preserved on a per-command basis. (I.e., I thought you could only say "preserve vars X, Y, and Z for each command, and that you couldn’t say “preserve these environment variables regardless of what command I run”. This was due to me misreading OpenBSD’s doas.conf manpage (doas.conf(5) - OpenBSD manual pages). The Arch Wiki page for doas at doas - ArchWiki corrected my understanding here, the syntax to use for enabling an environment variable to be passed through on a per-user or per-group (rather than per-command) basis is apparently:
permit setenv { VAR1 VAR2 } :group
I’ll amend my original post to reflect this.
To follow up on my previous review of doas porting feasibility, I’ve taken a look at both Kicksecure and Whonix running under Qubes OS. Here are the results. Just like before, a checkmark means “looks like it can be ported” or “isn’t necessary”, while no checkmark means it’s likely to be problematic.
/etc/sudoers.d/qt_x11_no_mitshm
- Specifies an environment variable to be preserved that affects all utilities on the system that leverage Qt. Depending on how exactly this rule is used, this could be trivial to translate, or it could be slightly tricky.
Defaults env_keep += "QT_X11_NO_MITSHM"
- translates to (roughly):
permit setenv { QT_X11_NO_MITSHM } :sudo
/etc/sudoers.d/qubes
- This looks like a generic account-wide nopasswd exception for the
qubes
group. There’s some SELinux stuff going on with it that can’t be ported, but since Kicksecure is based on Debian I don’t expect this to be a problem (I don’t believe SELinux is even used in Whonix or other Debian-based Qubes).
/etc/sudoers.d/qubes-input-trigger
- Contains several NOPASSWD exceptions for starting various Qubes input-related services as root. There are four sets of nine services each, each set is handled by one line of sudoers config, which covers all nine services with the help of a regex match. We don’t get regex matching in doas, so this would have to be replaced with 36 lines of doas configuration. Not great, but not horrible.
user ALL=(root) NOPASSWD:/bin/systemctl --no-block start qubes-input-sender-keyboard@event[0-9].service
- translates to
permit nopass user as root cmd /bin/systemctl args --no-block start qubes-input-sender-keyboard@event0.service
, plus eight more lines withevent1.service
,event2.service
, etc.
/etc/sudoers.d/umask
- Trouble. This one changes umask settings for sudo commands in general. doas handles umask configuration entirely on its own and does not allow the end-user to configure it. Thus this cannot be translated. Depending on what doas’s umask settings are and how vital this configuration is, this may or may not be a blocker.
edit: somehow the O in “OK” got replaced by a smiling emoji, fixed it
One question that does come to mind is, the Qubes-specific config is coming from Qubes OS, not from Whonix or Kicksecure. Porting things to doas means that some of Qubes OS’s software will need to be ported to be doas-compatible also, which may or may not be something they’re interested in. In the worst case, we’d end up having to maintain sudoers support for Qubes, and only providing doas support for non-Qubes. Maintaining both sounds like it could be difficult. Might be worth filing a feature request in Qubes OS?
dpkg -S /etc/sudoers.d/umask
qubes-core-agent: /etc/sudoers.d/umask
Will need to open a ticket at Qubes.
Related:
Will also need a ticket.
Yes.
Yes, please.
I just did a quick test, and it appears that processes launched via doas simply inherit the umask of the caller.
[user ~]% umask
022
[user ~]% doas bash
root@localhost:/home/user# umask
0022
root@localhost:/home/user# exit
exit
[user ~]% umask 077
[user ~]% doas bash
root@localhost:/home/user# umask
0077
root@localhost:/home/user# exit
exit
[user ~]% umask 000
[user ~]% doas bash
root@localhost:/home/user# umask
0000
root@localhost:/home/user# exit
exit
Similar behavior is observed when using doas zsh
rather than doas bash
. This may be sufficient to work around the inability to configure umask in doas.
upstream feature discussion: 'Investigating adding functionality to doas' thread - MARC
Late, but better late then never… How about run0?
Advantages:
- Speak for itself on its homepage.
Disadvantages:
- Increases dependency on systemd, but moving away from Debian (systemd based) is not very likely anyhow (Requesting a Port to a Different Base Operating System) as well as for reasoning documented on systemd.
- No credential caching yet. (run0: persistent authentication feature (if possible, probably not) · Issue #33366 · systemd/systemd · GitHub)
I don’t really think we should go with run0:
- We won’t be able to migrate to run0 until the release of Trixie, at least. run0 was added in systemd 256, Bookworm is using systemd 252.
- It doesn’t appear possible to configure run0 to run commands without requiring a password. That’s a dealbreaker, we have too much stuff that needs to be run as root without a password. (I mean, I guess we could try to migrate everything that needs to run as root passwordless to systemd, but that sounds difficult or potentially impossible.)
- It’s unclear how to configure it at all - it’s configured “by polkit”, but polkit is a generic authorization framework, it doesn’t allow you to specify specific commands and arguments the way sudoers or doas config does. pkexec works by using an “annotation” in polkit whereby you basically tack on extra info to a polkit action so that pkexec knows how to authenticate what, but run0 doesn’t use that. How would one configure certain environment variables to be allowed to pass through while denying others? No idea, it might not even be possible.
- It’s larger than doas. Way larger. run0 (really systemd-run) is 2642 lines long (including newlines and whatnot), and is heavily tied into the systemd codebase, which is about 1.3 million lines of C code. It’s unclear how much of that could be used to exploit run0, but some of it quite possibly can. doas on the other hand is relatively isolated (the only library it uses beyond the C standard library is PAM), and is only 1,850 lines long. Ergo, less attack surface.
There’s a few other issues or at least concerns (for instance you can pass through arbitrary environment variables using the --setenv
argment, the only reason this isn’t a security vulnerability that I can see is that you can’t configure run0 to run a command without a password), but I don’t think it’s practical or advisable for Kicksecure or Whonix to use run0. I think we’ll be in much better shape if we stick with doas. Thanks to doas’s isolation, we can probably audit it easier too if we choose to do that.
Excellent points on run0
, thank you! So if anything, let’s stick with doas
.
Actually, I was just considering, a “sudoless” design. It might be possible. Development notes are here:
In that case, neither a port to doas
would be required (nor a run0
port would be required).
Hmm, sudoless comes with its own unique set of challenges as well, though it looks hopeful. Some notable hurdles from an initial quick skim:
- The following things in Kicksecure and Whonix will probably break if sudo isn’t usable by the end-user. These aren’t just things where the user can just boot into admin mode when needed, these are things that will break the user-mode user experience.
- bootclockrandomization
- sdwdate
- setup-dist (in particular the easyorca feature, but it looks bitrotten?)
- tb-starter (this one in particular will break badly)
- tb-updater (this also may break pretty badly)
- Various things in usability-misc
- (maybe?) anon-gw-anonymizer-config
(I have a more detailed list of stuff here, but it’s not polished enough for me to publish yet, some of the more complicated packages I didn’t audit fully.)
- Many of the features here cannot be implemented by using systemd services or other background things. We will still need some way to run certain commands as root, even in user mode (this will be important for doing things like enabling Tor Browser to be launched even when /home is mounted noexec). I have an idea for this that would be written in Python and would avoid any use of setuid executables, but we will need something along these lines for things to be practical.
- How will Qubes OS VMs handle this? Will they just run as admin automatically and not use user mode at all?
How so? It has no sudoers exception.
This one we can say “boot into admin mode”.
Needs re-design.
We’ll just break the functionality as long as doas
isn’t installed. As long as Tor Browser is unavailable as a Debian package [1] and thereby properly installed into the system and keeping out executable of the /home
folder, Whonix probably should not enable noexec
[1] for /home
by default.
Qubes has a separate ticket. → Qubes sudo / su / root Hardening - Development Discussion
Qubes default is to install qubes-core-agent-passwordless-root
. The plan for Kicksecure, Whonix is to no longer install qubes-core-agent-passwordless-root
by default. Users will then be advised to open a Qubes Root Console instead.
[1] Would stable Tor Browser deb package help or burden whonix devs?
[2] Enhanced Security via Mount Options and Compiler Restrictions
True (I believe, working off memory and didn’t double-check), however there’s a GUI script for it that doesn’t seem like something that can be used in admin mode (it only applies to each specific boot). I guess it is a privileged operation though, so it probably is something we’ll just live without.
We’ll just break the functionality as long as
doas
isn’t installed
hmm, I guess it won’t be that much of a problem based on the research I’ve done so far. We will lose the ability to restart, stop, or even view the logs of sdwdate though, is that acceptable?
We will lose the ability to restart, stop, or even view the logs of sdwdate though, is that acceptable?
If worse comes to worse, yes. sdwdate-gui could show restart/stop actions only if started as admin.
As for logs, a sdwdate-logs.service systemd unit, doing something like the following would likely work (simplified):
journalctl --boot --output=cat -u sdwdate > /run/sdwdate/sdwdate-log.txt
In practice, sdwdate-log-viewer would need to be adjusted to do that. (Or something similar to sdwdate-log-viewer.)