Hacker News new | ask | show | jobs
by kokada 414 days ago
I am not sure if memory-safety is the biggest issue in sudo design. I find the fact that it is a setuid binary a much bigger issue because a bug can possible result in privilege escalation.

I found an alternative implementation that doesn't rely in being a setuid binary like systemd-run0 much more interesting from a security perspective, but I am no security expert.

4 comments

Right, but now the vector for privilege escalation will have to be a logic bug in memory-safe sudo instead of either a memory corruption (see CVE-2021-3156) or a logic bug. It’s hard not to see this as a major improvement.
A major improvement would be to get rid of glibc altogether. As long as glibc is the default, the problems persist.
Being a setuid binary means that sudo also suffers from attacks where an attacker runs `sudo ./malware` and then convinces the user to authenticate. Depending on how sudo authenticates phishing attacks or password reuse from another breach can be used to escalate privileges.
I don't think you can realistically enforce a security boundary between root, and a user account that occasionally elevates.

You can enforce a boundary between root and an account that never elevates though. And as far as I understand hardening sudo helps with that.

Why not? The way Windows does it should work in theory I think?

Maybe you can't realistically do it on Linux, because Linux doesn't care about desktop security and doesn't have the kind of privileged GUI that you need.

Windows is a bit different I suppose. Many pieces come together to make it kinda work there.

* Privileged gui to display and approve what will run as you mentioned. In Linux, non-privileged gui is used to request permission to do... something.

* Executable verification. Let's say someone with user level permissions swaps out the program you wanted to run for a malicious one. The replacement would not pass certificate checks which would be revealed in the privileged gui. Maybe you could supply an old version with known vulnerabilities though idk?

* Kinda commandline parameters verification. In Linux-land you can pass parameters to the program those could be intercepted with user-level permissions. In Windows this would be displayed in the privileged gui. However! The parameters are only visible if you click "show more" which I would guess <1% of people actually do.

As an example of the last point I tested making a shortcut to cmd.exe and used Run As Administrator. Then I changed the shortcut to C:\Windows\System32\cmd.exe /c calc and again did Run As Administrator. Opens calculator instead of command prompt with identical approval gui (except with show more).

The way Windows does it is users are prompted to elevate permissions, and can be tricked into clicking "Yes," just like users can be tricked into using sudo.
Well yeah you can't enforce any security boundary if your threat model includes "user might be tricked".

It can't be enforced on Linux because `sudo` can be trivially MitM'd, but you can't do that on Windows because it's just a click.

>I don't think you can realistically enforce a security boundary between root, and a user account that occasionally elevates.

So stop doing that!

Who are you shouting at?

Going back to the topic of the discussion, making sudo more resilient prevents a whole class of possible bugs (see CVE-2021-3156). You may not like sudo, but it is very commonly used to manage access, prevent accidental errors, or improve accountability on Linux servers and workstations. It is not going away. Therefore, improving sudo is a worthwhile goal and a thing to be celebrated.

I'm not shouting.

>sudo more resilient prevents a whole class of possible bugs

Good, but this doesn't fix the easiest way to escalate privileges as an attacker through sudo. Memory safety doesn't help people who run "curl | sudo bash" to install a random program from the internet.

>It is not going away.

But if work is done it could become very niche and eventually stop getting new usage over time.

What should you do instead?
Capabilities. Proper microkernels already do that
Design the system so that you do not need users to escalate to root. Find each use case where a user may want to use sudo and then come up with an alternate way to accomplish that action from a regular account.
Those will also have to be fixed/considered, but do not detract from the contribution of removing memory safety bugs which may enable exploits.
This is a case of doubling down on bad design. To me it's wasted effort preventing theoretical bugs in niche setups.
I think the opposing view is that moving away from sudo is substantially more effort and would break basically everything to accomplish "the same" thing as robustifying sudo (for some very loose definition of "same")
Yes, it's more effort, but it's not close to being the same.
Even with a new, perfect paradigm, there would be billions of systems running sudo for years.
I don't see how this attack is related to the setuid binary. No matter what method you provide to the user to elevate their privileges, they can be tricked into doing it. If it was provided by a daemon, built into systemd, or anything else, the problem would be the same.
It's related because malicous code can use the setuid binary to elevate its privileges.

>If it was provided by a daemon, built into systemd, or anything else

Yes, this is also dangerous.

So what's your recommendation? Removing the user?
> Being a setuid binary means that sudo also suffers from attacks where an attacker runs `sudo ./malware` and then convinces the user to authenticate

So does your OS.

Do you have in mind a design that enables users to escalate privileges while preventing them from being tricked into escalating privileges?
A bug in a daemon-based sudo alternative would surely also result in privilege escalation?

I think the main benefit of eliminating setuid binaries is that you can forbid them system-wide (e.g. via mount flags), as a hardening measure.

There's value in always starting processes from a known-secure environment rather than attempting to transform a user's arbitrary environment into a secure one.
True, CVE-2021-4034 comes to mind as a recent example (exploiting zero-length argv)
How is that any different than a daemon that has a parser error in its message handler, except that the daemon could be misconfigured to listen on a network socket?

The original unix process abstraction was extremely simple; the entire spec is a few pages.

The problem is that Linux keeps adding more and more levels of Rube Goldberg machine to its security model, so now literally no one understands how a default minimal install of, say, Ubuntu works.

Adding a magic daemon that runs stuff as root to this pile of complexity probably won’t help. Ripping out almost all the cruft that’s accumulated over the years, and adding back something sane (maybe BSD jails) would work a lot better.

> How is that any different than a daemon that has a parser error in its message handler

The non-daemon has to parse just as much in addition to making itself secure. Actually it needs to parse more things in more complex ways.

Assuming static linkage (which sudo has to assume), there’s really not much to parse. It should just be dealing with a null-delimited list (argv) and the caller’s environment variables (which it just needs to ignore and clear by default).

Here’s a simple implementation: https://github.com/TheMilkies/rut/blob/main/rut.c

(Though it doesn’t clear the environment unless I’m missing something - they should probably replace the call to execvp with one to execvpe, and add a null pointer to the end of the argument list).

The problem of setting up root’s environment and parsing the command line is left to the shell in both solutions (the thing I linked doesn’t indirect through a root login shell).

There’s also the config file, but that’s the same for both.

Similarly, the system could be running some SEL derivative or be using a capability system that causes non-standard behavior from system calls, but the daemon has the same problem.

I think this post explains why much better than I can: https://mastodon.social/@pid_eins/112353324518585654.

So yes, I am not saying that privilege escalation bugs are impossible if you have a different architecture, but like Lennart argues is that it makes them much more difficult to happen, especially because creating a proper setuid is difficult. Also there is a bunch of things that makes sudo especially tricky to implement correctly.

I used to be annoyed that sudo would reliably crash from memory errors.

Eventually the bug (and associated vulnerability) was patched. I think.

Rust version of sudo had lots of ridiculous logic bugs. I do not see the improvement.
Do you have an example of the logic bugs you're referring to?
I am pretty sure it is around here somewhere: https://github.com/trifectatechfoundation/sudo-rs/issues.

I apologize, I do not bookmark these issues, but maybe I should start doing that? In any case, you will find logic bugs which may raise the question "is it really worth the rewrite?".

A more interesting link is https://github.com/trifectatechfoundation/sudo-rs/issues?q=l... IMO. Glancing down that list, a lot of them aren't what I would personally view as major problems (ex. "rustup is inappropriate for security critical software" - maybe it is, but that's not a specific exploitable bug), but I would suggest https://github.com/trifectatechfoundation/sudo-rs/issues/575 as a potentially interesting looking example.

> I apologize, I do not bookmark these issues, but maybe I should start doing that?

Yes. If you want to point out problems, it really helps if you can point at specifics.

> In any case, you will find logic bugs which may raise the question "is it really worth the rewrite?".

There's a cost/benefit question, but note that the mere presence of some bugs doesn't make a rewrite worthless.

Thank you!
You have the burden of proof to substantiate your accusations. Until then they're entirely unfounded.
Aren't full rewrites pretty much universally considered harmful?
No