Hacker News new | ask | show | jobs
by yakubin 1318 days ago
Sudo must be the program with the largest number of buffer overflows I’ve heard about. That news is repeating itself ever since I remember.

Maybe a good time to plug doas, a simpler alternative to sudo from OpenBSD folks[1], developed partly due to security fears about sudo. It’s also been ported to Linux and is available in e.g. Alpine and Debian.

[1]: <https://flak.tedunangst.com/post/doas>

11 comments

To put the relative simplicity into perspective, here is the official Github mirror of sudo:

https://github.com/sudo-project/sudo

On the contributors tab:

https://github.com/sudo-project/sudo/graphs/contributors

We can see that sudo has been maintained by one person for ~29 years who has single-handedly committed ~2,936,000 changes over that time resulting in a net increase of ~480,000. It is also being actively developed with ~270,000 changes resulting in a net increase of ~40,000 lines in the last twelve months.

In contrast doas is, just eyeballing it, maybe ~500 lines and at most 1000 lines all together.

From a security point of view, staying small reduces attack surface. So if this holds all the features you need, that’s a valid option.

It doesn’t remove a bit of how impressive the dedication of Todd C. Miller is of course.

These are two solutions with a common core goal but greatly different concerns.

Todd is a saint for the work that he does here. Ultimately, like many other OpenBSD-related decisions, sudo was replaced by doas because of all the security-related issues with the code. Oftentimes, OpenBSD will replace a very functional solution, that has too many security issues, with one that has far less security issues and is, simply, good enough.
> ~2,936,000 changes

I don't think it makes sense to add all added and removed lines together and call it "changes": for example, this counts even a single character typo fix as 2 changes.

why on earth is sudo so complicated. All I want it to do is: ensure authorization, raise privileges, call exec.
> All I want it to do is: ensure authorization, raise privileges, call exec.

A lot of people do want to do more, especially in some corporate contexts people run very complex sudo setups.

Consider something like Linode; maybe you want some of the more experienced support people to issue some commands on some machines, without having full control. And you've got a gazillion machines so you don't want to setup each one individually (as well as revoke access once they leave). Things can get fairly complex pretty quickly once you move out of simple settings.

For my desktop machine, doas is perfect. For our servers it's fine too because we have just a few people with access. But I'm not everyone of course.

doas was explicitly written to NOT cover all use cases, and that makes it better for the (simpler) use cases it was intended to solve, at the price of not covering other use cases of course.

Maybe I’m misunderstanding you but doas handles the use-case you describe. I can enforce that some users can issue some commands on a given machine in doas.conf

As someone who manages infra including Linux and OpenBSD and does configure sudo and doas in this way, I’m pretty sure 99% of users would be fine with the simpler tool. Maybe the simpler, safer tool should be the default.

I don't think doas can integrate with PAM, LDAP, and all of that, and the possibilities doas.conf give you are vastly less than what the sudoers file gives you.

> I’m pretty sure 99% of users would be fine with the simpler tool

That probably sound about right, give or take a few %; it probably should be the de-facto default, with sudo being used when doas doesn't suffice. But the question was "why on earth is sudo so complicated?", and the answer to that is "because some people want/need complicated stuff".

From a security standpoint point you would want the opposite, the stricter doas on the more exposed servers and and the less strict sudo on the personal desktop.
That's the problem. We use sudo that autorizes user by it's SSH key via its auth socket... so we can essentially authenticate sudo via smartcard (Yubikey), and not keep the private key on user machine.

Some other folks use LDAP to get the sudoers files or even allowed ssh keys itself

There is also "just run thing as user" but also "set up same way shell would and pretend user logged as different user", first one is simple, second is a bunch of setup, copying env variables etc.

There is a good argument for splitting "just run app as different user" and "everything else that has to do with interactive shell and admins doing things on server" but now you have 2 configs to manage...

"ensure authorization" and "raise privileges" and "call exec" are all behind plugin-based architectures to allow for people to set up various ways to do things. The simple example: why do you only need to type in the password once per session/30 minutes calling sudo in most environments? How can people set things up with a hardware key? How do you make just some commands work and not others?

That being said I don't think sudo's code is complicated? It's big because it has all of these plugins supporting various mechanisms, but each file is pretty straightforward, and the control flow is really not that hard (after you get that it's plugins).

> All I want it to do is: ensure authorization, raise privileges, call exec.

And have an audit log? And clean the environment? In particular the path? Dynamic library path?

Still, I suspect "ensure autz" is the problem (implies Pam, 2fa, kerberos, etc etc).

Probably because of sudoers?
The documentation describes the configuration as a context free grammar using EBNF notation. This is impressive, but maybe a little more complicated than I want to get with a basic security tool. I suspect most people who don't have to modify it very often are going to secondary sources, like tutorials or stack overflow, and copying examples from there.
IMO, a more complex grammar allows for better descriptions. The only real type of grammar simpler than CFG is a regular expression. That's pretty limited, although (the older part of) CSS doesn't need more than that. But as soon as you want a nested construction, hierarchy or simply nested parentheses, you need a CFG. If it's difficult to configure, the problem is the (configuration) language, not the power of its grammar.

And there are excellent parser generators out there. You don't have to fear introducing bugs via them.

Yea I sometimes have to refresh my memory on sudoers or just search for what I want to accomplish, hoping that someone has already handled the potential security gotchas (eg, exact fullpath command should always be specified).

I agree, in some typical cases I only need to specify "<user> can become root" or "<user> can become <user of group>", kinda like doas already does I think.

I'll probably try out doas when the next such special need arises, then resort to sudo if doas is insufficient for some reason.

> [...] as a context free grammar using EBNF notation. This is impressive, but maybe a little more complicated than I want to get with a basic security tool.

I apologize if I'm being trite, but Context Free Grammar doesn't mean that the semantics of whatever that grammar describes is simple. It just means that it's simple to parse into ... something. Parsing a CFG is also not impressive in the slightest. It is, in fact, trivial since the 1970s. Anyway,

You shouldn't be scared of the CFG bit... you should be scared of the semantics.

I also wonder....

    function sudo { su -c "$@"  root }
though I guess half the struggle is enabling sudo without a password
"sudo" asks you for your individual password. "su root" asks you for a single root password
To be precise, whether sudo asks for your password or the target's password is configurable, and different distros have different defaults.
I wonder how many other tools we "take for granted" are similar to these these conditions.
All of them.
> It’s also been ported to Linux

Last time I checked there were several different ports floating around. Now I see at least Debian has chosen opendoas, I guess people have mostly converged to that one. Also fun stuff like https://xn--1xa.duncano.de/slicer69-doas.html

The point being that while openbsd doas is undoubtedly very nice, the linux ports are separate projects

Been maining opendoas for a while now. The main problem I have with it is that the "don't require a password for ___ seconds" timeout is unconfigurable as far as I'm aware. So you have to enter your password fairly frequently, which can be annoying on non-sensitive machines.

But for simple systems that aren't running complex user privilege management, doas is very much a great replacement.

I don't see any tests on the github. Is there some way to do pipelines for open source projects that wouldn't require funding? Would a free gitlab tier account for stuff like this be within the TOS? I just find it kind of crazy how most of the open source ecosystem has no static analysis or unit tests. I'm not criticizing, I'm trying to figure out how to contribute.
Github does allow (some amount of) GH Actions for free, as does Gitlab.
It does but it's kinda a pain for use for anything but scripting languages in my experience.

They way it scales doesn't fit well with C/C++/Rust/Scala/Java/etc. build systems and test runners.

I'm also having problems with it at work all the time, like task randomly being reported as canceled after they already passed. Or task after completion hanging for well over 30min until some internal timeout triggers and they then get reported as failure. Or a task being reported as succeeded to the UI and as failed to follow up tasks. (All issues I ran into just in the last week :=(, some might be caused by us having to use local GH Actio runners due to how GH Actions work, but I also have seen all this problems before we started using local runners so probably not).

> The main problem I have with it is that the "don't require a password for ___ seconds" timeout is unconfigurable as far as I'm aware.

https://wiki.archlinux.org/title/Doas#doas_persist_feature

https://wiki.gentoo.org/wiki/Doas

With the persist keyword doas can remember an authenticated user and will not require confirmation by password for five minutes.

Indeed, I've been looking around somewhat during off-time with a colleague how much we actually use of sudo, and what doas couldn't do. We're indeed looking at starting a migration, because some DNS based, LDAP integrated, PAM integrated, really complicated priviledge escalator is becoming kinda scary as of late.

The biggest difference we found is that sudo is a little more convenient to manage with a config management solution, since each piece of config management code can just drop a file in /etc/sudoers.d. With doas, we have to coordinate a bunch of parts of the config management manipulating one file, /etc/doas.conf. This always turns out a bit messy. But maybe we'll just merge everything into one big and somewhat messy monster doas-conf-template with a ton of feature toggles and loops and go from there.

But beyond that, almost all of our sudo rules are 2-3 patterns: Admin can sudo as everyone, zabbix/telegraf can run data gathering commands, and maybe some other automation triggers like pgbackrest wiping a postgres data dir during a restore, that's about it. All of those are pretty trivial doas rules all in all.

The biggest difference we found is that sudo is a little more convenient to manage with a config management solution, since each piece of config management code can just drop a file in /etc/sudoers.d. With doas, we have to coordinate a bunch of parts of the config management manipulating one file, /etc/doas.conf.

Apparently whether it's used is configured at build time, because I get different results trying it on Arch and Alpine, but doas absolutely has a /etc/doas.d

EDIT: Oops, apparently Alpine added that - https://git.alpinelinux.org/aports/tree/main/doas/configurat...

Mh. I'm kinda sad that this is a distro patch. If that was upstream, we'd be using doas at this point in a few sideline setups, I'd guess. Plus, exploiting a directory list or writing files to a rather niche and secure directory generally requires rather high degrees of privilege and usually implies that the system is owned as a whole anyhow.
> EDIT: Oops, apparently Alpine added that

This seems like a really weird thing for a distro to add themselves rather than upstream.

not really, alpine really wanted it. openbsd did not, it was a simple patch. you are probably going to maintain a patchset anyway(for the port to alpine) might as well maintain one more to support a simple feature you really want.
It looks like doas is missing some important features sudo has, notably full I/O logging and wildcard and in the newest version regex support for matching arguments. The latter could maybe be worked around with wrapper scripts, but I don't know what you would do for logging. And the password persist option is experimental, and not configurable on Linux.

If you don't need those features, doas is probably a good replacement. But if you do, it probably isn't an option.

> It looks like doas is missing some important features sudo has … and wildcard and in the newest version regex support for matching arguments.

Sometimes less is more. My immediate response to that is that it sounds like needless complexity which can be a source of errors, bugs and security-vulnerabilities.

What typical use-cases do these particular features have?

> What typical use-cases do these particular features have?

For the io logs: auditing. And in some cases such logs are necessary for compliance reasons.

For wildcards: allowing to run a command, but only if they supply a specific option that makes it less dangerous. Now, you do have to be very careful when doing that, but there are cases where it is useful and explicitly listing every variation of options that is allowed isn't practical.

I also forgot to mention sudoedit. Although, making something similar for doas would be pretty simple, so I'm kind of surprised there isn't something.

For wildcards;

Allowing a user to use systemctl with specific daemons, so ```systemctl * unit-name```, without a password. But anything outside of that I need a password.

It's actually good to not support such things, because it makes it way too easy to give more permissions than you intent to. In your example it effectively gives unlimited root access, as you can do `systemctl edit unit-name` and change the unit to run arbitrary programs as root.
Depends on what you do. If you have app server and use it to give access for developers to restart their apps, them getting root on the server is entirely irrelevant.

It's more so the curious dev don't just go sudo bash and changes stuff willy nilly then forgets what they changed.

We do avoid wildcards like plague but honestly regexp support would be more useful, then our devs could just have say

    ^/bin/systemctl (start|stop|restart|status) app-([a-z0-9\.\-]+)$
and be pretty safe.
Sure. But the simplicity of adding a wildcard makes it very easy for sysadmins to make a too simplistic configuration, which in turn ends up being a security vulnerability, maybe even if the code in sudo itself contains no faults.

To me this sounds like a feature for a non-default "root-manager", while the default should be kept simpler to avoid people falling into such traps.

You lost me somewhere between "regexp" and "pretty safe."
That's all well and true, but it's an expected downside which you'd see with any software which needs to be properly configured to run. If a user doesn't know they should take this seriously by ensuring that a tool which potentially grants root privileges is correctly configured, that shouldn't stop others who know better.
Yeah, why is that a command anyways...

But the point being that the users who have that also can just sudo anything anyways, and if an attacker is running shell commands, you're already in trouble.

I'm wondering if you're not right at this point though.

As meme as it is, Rust rewrite wouldn't be out of place...
> Sudo must be the program with the largest number of buffer overflows I’ve heard about. That news is repeating itself ever since I remember.

That you've heard about. There's two big reasons: (1) people often don't try to spend a lot of time finding exploits for userspace programs that don't open network ports or perform privilege escalation. And (2) when they do find exploits in those programs, they don't make it to HN.

I was thinking the same, this is the slackbuild for Slackware 15

https://slackbuilds.org/repository/15.0/system/opendoas/?sea...

It also contains some information on how to setup doas on Linux

There must not be a single suid program in a safe system. The concept of suid bit is flawed and nothing but a hack. You can build sudo-like functionality using ssh @localhost and additional root user with special shell.
That to me sounds like moving the problem from a privileged binary to a privileged daemon and putting a network stack in the middle. I don’t see how it solves anything. Any way you can secure sshd you can probably apply to the suid binary as well.
This requires enabling being able to log in as root, which I'd rather not enable.
And that sshd server is running as root, which is really just the same as setuid except with extra steps.
To be honest, your solution sounds far more hacky than a suid bit. A suid bit is effectively just a mechanism to implement privileged access in user space. I don’t see what’s hacky about that.
> Sudo must be the program with the largest number of buffer overflows I’ve heard about. That news is repeating itself ever since I remember.

libxml? zlib? PHP?

The déjà vs are many…

Or just uninstall sudo, at least on opensuse it is optional package.