Skip to content

Comment on Bringing Memory Safety to sudo and su

Comments

My concern is that while re-implementing sudo in rust would solve bugs due to memory safety and off by one errors, it is a complex piece of software where logic errors can create serious security issues.

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-2280...

You are not wrong, but logic errors are a pervasive concept that applies to all code bases. Logic errors in the existing codebase, as you've demonstrated, can also cause issues. The pro-Rust argument here would be "letting the compiler handle memory safety for you frees up your attention to focus on those logic errors even more."

Time will tell!

That's not really responsive to the concern. The issue is that we've already had decades of experience with the existing sudo codebase looking for logic vulnerabilities. And, in fact, that's what the overwhelming majority of sudo vulnerabilities are; they're not generally memory safety bugs. So rewriting in a new language to get rid of memory safety vulnerabilities is not, in fact, an obviously good tradeoff.

I don't directly disagree with what you're saying here either. All of these things need to be weighed against each other. I am not familiar with sudo's codebase, and so I can't speak to if I personally agree with Prossimo or you here.

What I will say is that I certainly agree that memory safety on its own would be a weaker justification for the reasons you cite. But this analysis doesn't take into account the relative usefulness of various language features for preventing logic errors. For example, I find that enums really help catch edge cases that are easy to forget about, causing bugs. Tagged unions are obviously a thing in C codebases but aren't as easy to use nor integrated into the language in useful ways, like exhaustiveness checking. You're absolutely right that, at the moment, the sudo codebase is more well understood, but one could make the argument that C's various weaknesses in areas like the typesystem means that as this codebase matures, and becomes well known itself, logic errors become more tractable.

One could also make an argument that a new codebase is a good idea, even disregarding the C vs Rust factors. For example, they're not going for "100% drop-in replacement for sudo," they're going for "a drop in replacement for common cases." Sudo has users who I assume would be upset at removing features they rely on, whereas this project has no userbase, and therefore, can do whatever they'd like. Removing a bunch of code can also help reduce logic errors, as it's impossible to have logic errors in code that doesn't exist, obviously. Of course, this article focuses on the memory safety aspects and not the others, maybe that's a marketing mis-step. Then again, what's important here is the engineering, not the marketing.

So yeah. It's not obviously a slam dunk either way, it really depends on how one personally weighs all sorts of factors. As I said above, time will tell.

While I appreciate Rust's correctness features and dearly miss `match` statements, as a software security professional with (I think I can say) a lot of experience looking for the kinds of vulnerabilities we're talking about here: I do not buy this theory of Rust's security advantage, like, at all. People have been saying things like this about strongly typed languages of varying sorts (Haskell was once a favorite) for over a decade, and it hasn't panned out. I think you'll find, if you look at the last (say) 10 meaningful sudo vulnerabilities, that there isn't a clear story about how enums would have steered you away from the problem.

Certainly, if there's an appetite for a reduced-fat version of sudo that caters to the 80-90% use case, I'm all for a Go, Rust, or whatever version of that thing. But then, C programmers were making the same argument 15 years ago, and nobody was able to sell the reduced-fat sudo (or, for the matter, the reduced-fat ssh, which we're all still dealing with). If it works out, great.

If it ends up gradually becoming a 1:1 equivalent to sudo, wartfeatures, and all, that's less great.

I do not buy this theory of Rust's security advantage, like, at all.

Don't worry, you've made that overwhelmingly clear.

(I also know that I am not a security engineer, and respect your overall expertise here tremendously.)

that there isn't a clear story about how enums would have steered you away from the problem.

Yeah man, I picked an example solely based on something that's done in both languages, but differently, because I thought it would be illustrative of the general idea. I am not claiming that enums will magically fix CVEs in sudo, that would be ridiculous. I'm saying "if we're saying memory safety is irrelevant, and logic errors are what matters, you should compare the tools that let you model your problem." Maybe Rust's features are truly irrelevant here, but as you say, I dearly miss match statements when I'm working in a language without them, so I suspect they do help in the general case of this argument, even if they don't for this one specific codebase.

People have been saying things like this about strongly typed languages of varying sorts (Haskell was once a favorite) for over a decade, and it hasn't panned out.

I actually agree with this, but I don't think that the typesystem aspects are the cause here. Programming language adoption is weird, complex, organic, and really hard to see the future of. I think it's taken decades to "productize" more advanced type systems, and it's really only relatively recently (like, I'm not gonna try and pin down an exact moment, but like, let's say "the last ten years" but I suspect even that may not be far enough back) that we've seen larger adoption of this stuff. I don't even personally consider static typing to be strictly better than dynamic typing!

Oh and, if we're gonna nitpick examples, Haskell was never going to be a language to do that, one that expressly doesn't try to pursue popularity and broad usage. Those people (and I remember them too) were wrong then, and wrong now. But that's not (only) the fault of the type system.

That said, while I agree with the description of the history, I don't see how the trend points to this being impossible, but rather than we're now living in the time of truly being able to answer the question one way or the other. And the only way you do it is by putting in the work.

I'm aware that there is more to Rust than enums, and that you were using that as an example of a correctness feature that is part of a gestalt of correctness features. My point is that people have been arguing that more expressive languages with stronger type systems will be better able to model problems and thus avoid logic vulnerabilities, and that hasn't panned out at all.

Since I don't think there's any evidence to support your point that's a Google query away from you, I guess something you could present that would weaken my argument is an example of a recent meaningful sudo vulnerability where idiomatic Rust, written in the manner that a typical Rust programmer would use to solve the relevant problem, would have foreclosed on that vulnerability. Obviously: we pre-agree about memory corruption vulnerabilities here.

To be honest, on these issues, I'm not invested in winning an argument about it. I can see good arguments for why this would be beneficial, and I think they make sense. But I also know there's good arguments for why this would not be, and I can think they make sense too. I want to see both sides represented here, because I think it's interesting, and seeing both sides is good. That's good enough for me.

If in five years (or whatever) no distros use this new tool, it's had zero impact on things, I'll go "damn, tptacek was right," and that's an outcome I am totally fine with.

And, in fact, that's what the overwhelming majority of sudo vulnerabilities are; they're not generally memory safety bugs.

Only if you count all vulnerabilities as equal. There have been lots of sudo vulnerabilities over the years, but most of them either only affected configurations that allow users to run specific commands (unlike most configurations which are all-or-nothing), or had even more unusual requirements. I think the only sudo vulnerability in a long time that affected the default configuration is CVE-2021-3156 – and that was a memory safety bug.

Sure. That was the vulnerability I was thinking about too. I think the biggest knock I've heard against what Prossimo is doing --- and I respect & admire the people working on that project! --- from exploit-dev types is, they're picking targets that nobody thinks are likely to cough up more meaningful memory corruption vulnerabilities. I agree: 2021-3156 is a good argument for memory safety. Memory safety is a good argument! But if you're ranking "next things to make memory safe", sudo is, maybe counterintuitively, a little unattractive.

What's your ranking for "next things to make memory safe"? I'm going to guess the TLS stack would be #1, considering fly.io's sponsorship of rustls. Eager to hear the rest of the list.

I’m one of the people working on this. While I do think that the memory safety aspect is an important one, I think that one thing where we can win even more is that Rust has a type system that is much more robust than what C offers. If set up right, we can prevent lots of these kinds of bugs right from the start. We can also simplify things in lots of cases by removing unnecessary details no longer relevant in a modern implementation.

> it is a complex piece of software where logic errors can create serious security issues.

I know many unix commands have a lot of capabilities I never use, sudo? Not much logic other than "run this as root if user has permission" is there? OTOH I never thought about how a cli app can escalate privilige without already having it....

The escalating privileges part is easy: the file /usr/bin/sudo is owned by root and has the setuid flag set, meaning it gets executed with the permissions of the file owner instead of those of the caller.

The complexity has more to do with the fact that it has 28 command line flags, plus a fairly complex config file to configure who is allowed to do what, impersonating which user, and whether they need a password to do so. All of that dealing with security critical stuff like what exactly should carry over and what should be reset (all configurable ofc).

su is very simple by comparison (and you can do `sudo -s` anyways to get the same result as calling su without parameters).

it is a complex piece of software

That's the problem. It shouldn't be. I hope the sudo-rs variant does better.

Actually, there's a point: doas is already smaller and safer, so it would probably be easier to port to a new language as well as having less attack surface in the first place. Of course, it's still necessary to work with sudo as well because it genuinely supports a lot more features and some of them are even useful, but if you want the low hanging fruit...

They should just replace /etc/sudoers.d with a Domain Specific Language ;) /s

AboutSource Built by g1lg1l

Hackerly is an independent reader for Hacker News, built on the public HN API. Not affiliated with Y Combinator.