Good effort, and while I usually would like to see more GPL software, at least Apache2+MIT looks better than the little mess in sudo licensing: https://www.sudo.ws/sudo/license.html
I understand mail capabilities, but LDAP/Kerberos direct integration? Why is PAM considered bad here? That looks like a duplication of maintenance points in user/group management
I laud the effort and I understand that rust gets a lot of visibility here on HN, but when the motivation is to improve security, than why not use a language which goes through great length of ensuring such, e.g. the SPARK subset of Ada?
All my experience with opensource projects tells me that it's hard to have a healthy opensource project with a super-obscure programming language. The reason is simple: You won't get contributors. You have a hard time finding people doing anything in it.
I have no idea what the SPARK subset of Ada is. But even if it is superior to Rust in one aspect or the other, the fact that you will have a very hard time finding any developers capable of using it kills it as an option.
It's the kind of infrastructure project that doesn't really attract much interest, I doubt there would even be a single external contributor if it were written in some niche language.
Does that page only list Github accounts? Sudo is maintained using mercurial, the git repository is just a mirror. Try the official homepage for a significantly longer (and also incomplete) list of contributors https://www.sudo.ws/about/contributors/ .
Suppose you could have memory safety in C by implementing a borrow checker for every individual function. It would be suitable for certain industries, but breathtakingly expensive, error-prone, and therefore useless for most kinds of software.
That's roughly the situation today with SPARK. Using Ada does not automatically buy you memory safety on the same level as Rust. You can get a lot further with SPARK, but the annotations are very cumbersome to write.
These are well-known problems in the Ada community. There are efforts underway to improve SPARK's ergonomics by adapting ideas from Rust, with the help of the Rust Foundation. Someday soon, Ada will be much closer to Rust's sweet spot on the safety/productivity graph. In the meantime, there are CVEs to patch.
You don't need annotations to write memory safe programs in SPARK. With annotations you can verify properties of the program up to functional correctness which is not integrated in the Rust ecosystem.
Because they are not as good of a fit. Rust strikes an extremely good balance between memory safety and productivity. Also almost nobody knows Ada, and even fewer the flavor you mentioned
Both SPARK and Rust provide memory safety, so it's perfectly reasonable to use popularity as a "tie breaker". Applications are written by people; the more people who can usefully contribute, the more work can be done.
Seems obvious to me that ease of installation seems also is a factor where popularity can have an impact. If one is more popular that increases the likely hood that users will already be familiar with installation methods (ignoring actual difficulty), reaching more people in the process.
> What’s your source saying more people write Rust than Ada?
I think this "popularity" reasoning is flawed. It completely misses the context of the tool. Just ask yourself -- are there many UNIX CLI tools written in Ada/SPARK? I'm sure there are some, but not aware of any I use regularly.
Meanwhile, there is a Cambrian explosion of Rust CLI tools taking place.
"Popularity" is really a surrogate for "popular, accessible, infrastructure for an OSS CLI tool for UNIX", a place where Ada AFAIK has not been a first choice. If we were building firmware for a missile guidance computer, maybe the reasoning would be different?
But it's still not a sufficient reason, so I'll add another: People really like using Rust to make these types of tools. It's amazing to me that people are so willing to discount as non-technical, and therefore unworthy of discussion, lots of people really like using Rust.
In my other comment I wrote "open source ecosystem" in order to avoid all the speculation about how much SPARK is used in commercial avionics and whatnot.
Exactly. The point of a programming language is to translate human intention into machine instructions.
Whatever optimizes for the accuracy of the instruction output is the best. Sometimes it means language features. But it can also mean its popularity so you can get many more human eyes on the same bits of code.
Lots of people seem to be learning Rust judging by the last few years of Advent of Code.
In a safe language like Rust, the level of capability you get doing even say the first couple of weeks of AoC is enough that your small contributions to a project are likely to actually work and be more or less serviceable, so that's a huge help.
"Why didn't you choose [my language], it's obviously better at X?" has got to be one of the weirder open source Qs.
It reminds me of when the Ruby folks wrote their YJIT in Rust and there were a few Qs which were like -- Q: "There doesn't seem to be a security reason to write this in Rust, why not use C++?" To which, a totally reasonable A is -- A: "We like Rust (and there is no reason to be miserable forever)!"
People almost never choose a language for one reason (except for the people who use Ada, I suppose -- the reason is the government requires them to do so). Memory safety is a great reason to learn/choose Rust, but Rust is much, much more than memory safety.
Moreover, "Why are you ignoring Ada?" is "Why didn't you write/don't you rewrite this in Rust?" by a different name.
I love to see the broad move towards safer languages, but let's not forget that Rust is not the only safe language for system development. Plus iirc the model-checking ecosystem of Ada/SPARK is much more mature than that of Rust.
It looks like it's being done in rust because some rust zealots convinced Amazon to give them money to re-write su/sudo. It looks like it's not being done in Ada because Ada zealots couldn't convince anyone to give them money to re-write su/sudo.
This seems worthwhile at first sight; another implementation (in a different language) gives us more choice and time will tell on the CVE count:user ratio.
I assume the more unsafe rust used, the more the CVE numbers will appear like C and C++. People like to say unsafe means "I checked this and this is fine, compiler" and isn't a bad thing but I feel that's inaccurate since the whole point of rust is that people struggle to write safe code even when they are really checking. I feel unsafe rust is way more "I really hope this is right, but I have minimized it to just this area out of necessity, since it likely isn't."
I would like to see how much CVEs go down over time. The fact sudo is being rewritten suggests that even after long periods of use, security issues popping up is still a common-ish problem?
> security issues popping up is still a common-ish problem?
It seems to average out at a bit over 1 per year over the last 20 years, based on [1]; is that "a lot"? I guess?
It's worth pointing out that while there certainly are memory-related C-style issues, quite a few are logic errors because all of this is rather subtle once you start adding features beyond what e.g. "doas" does. For example the recent "Sudoedit can edit arbitrary files"[2] is a somewhat subtle interaction between sudoedit, environment variables, and flag parsing. Previously there was [3] and [4] from 2004 and 2010.
Will memory safety be a benefit? Of course it will. But I think these kind of issues are the real challenge here. A drop-in replacement for "sudo" is useful, but I have to wonder if it wouldn't be better to rethink the approach from first principles, taking 40 years of sudo lessons in to account. It's also surprisingly easy to shoot yourself in the foot with a wrong sudoers file, which is not strictly a security issue in sudo as such but also something that can probably be improved on?
That 2023 sudoedit bug has been in sudo since 1.8, released in 2011, and Todd has been maintaining sudo since 1994, and he's actually pretty good as well as experienced with this kind of stuff. Yet he still missed it, as did everyone else, for well over ten years. It seems there are far more structural problems in the entire approach that go well beyond "C is not memory safe". That's certainly an issue, but in a way seems almost banal compared to the deeper issues.
That's a really good point that I feel like isn't talked about enough. Unsafe rust is a lot harder to write correctly than bog standard C, because you have to uphold the invariants to avoid undefined behavior (1). It's why there's a whole ebook about it (2).
That doesn't mean it's impossible to write correct unsafe code, it's just not as obvious as "trust me bro I know better than borrowck." You can't actually elide the invariants Rust upholds, you just have to take over from the compiler when it can't prove them.
Another critical consideration of this is that if you make a mistake in unsafe rust code it could manifest itself as a 'bug' in the 'safe' rust code due to invariants that the safe code depends on not being upheld. It is literally undefined behaviour, in the "rm -rf / and insult your mother" sense.
Using grep, it looks like they mostly use unsafe code to interface with existing C libraries. In those cases it's roughly as tricky as writing C in the first place IMO, so still probably a net win.
How would I find the CVE's on sudo/su? I opened up mitre.org and cve.org, but searches for sudo/su brought up hundreds of issues (or more), and most of them were not about sudo/su. (It's a bit like searching for "The The"'s music on early Google.)
Rust has a minimal runtime (0), and links to libc by default which brings in the libc runtime (so it's not like C is any better). Except that the Rust runtime is written in Rust, which is nice for memory safety.
I don’t think people generally say secure, they say safe. Safe is necessary but insufficient for secure. The existing implementations assume safety by diligence. Rust promises safety by construction. That’s useful. But, to your point, insufficient. People that say secure when they mean safe are just wrong.
There is a code object called "C Runtime" (crt0.o)[1].
This was a good name at the time. Its a bit of code that gets executed literally "at runtime". When you run a program, this object gets invoked to setup the stack and call main(). Its just a bit of assembly.
Then, decades later, languages like Java overloaded the term "runtime" to refer to their interpreter / vm. This causes confusion to this day, evidently.
The term "runtime" is overloaded here. The C runtime is not what people usually mean when they say a language has a runtime.
There is a crt.0 "C Runtime" object. This is code that is literally run "at runtime". When you execute a binary, the C runtime is the first thing executed to setup the stack and call main().
This is just a bit of assembly that runs before main(). It shares ~nothing in common with "runtime" languages like Python or Java where the runtime is alive during the whole program's execution.
The C run time does not handle floats or threads or anything like that. Software floats are dealt with by the compiler and threading is implemented as its own library (either in userspace or built into the kernel).
Libraries and crt0.o and the like. Libgcc_s ; but it isn’t a runtime in the sense that some magic is doing GC or scheduling for routines. ABI that describes what the assembly should be doing, it isn’t a thing doing stuff.
If the goal is security, then there is more to it than just using a memory safe language. Otherwise the result of this, possibly unwittingly, seems performative.
how many of us had never even heard of sudoedit? I rarely see anyone using sudo features other than "run this with root".
given that sudo's security history has mostly non-memory-corruption/overflow faults, the big win would be refining/simplifying it, regardless of language.
sudoedit and visudo are mandatory on a host machine given the tendency for sudoers parse failures. Defaults env_keep = "" ? Oops, I guess sudo no longer works.
People unfamiliar with Rust constantly ask this question and the answer is always the same: because they're not reinventing the wheel and rolling their own cryptography, hash functions, etc. The more you do that, instead of using battle-tested existing libraries with plenty of maintainers, the more likely it is that you'll introduce a security vulnerability. Plus it duplicates effort unnecessarily, when it would be better to pool it.
For context, if anyone's curious, here's the dependency list:
This betrays a fundamental misunderstanding of how Rust and unsafe work. You sometimes need to use unsafe Rust for low level work or C/C++ FFI; that doesn't make the rest of your code unsafe as long as you A) use it only when necessary and B) ensure that the basic invariants are maintained and the basic contract between safe and unsafe code is upheld. This whole "well it uses unsafe in parts so its suddenly all unsafe and we might as well use C" thing is a bit silly.
I think it will be interesting to see how the memory safety gains from using Rust trade off against the potential logic bugs created by a full rewrite. (Or maybe there won't be any - I guess they can probably reuse the tests from the original?)
I know uutils/core-utils uses the old tests, which makes sense, that way you cover most of the intentional behavior. A more comprehensive method could be to generate a comprehensive set of random scripts with a capable LLM like GPT4 in identical vm's with the 2 different binaries and then log/diff each scripts behavior.
Is it only me or ….. when there’s a big news about a certain programming language within 2 days open source projects begin to pop up like they’re the main story
Well, it's also a suid binary, thus it's very safety critical on unix-systems. su isn't as complex as sudo, so there's less reason to create a "simpler su", but still, a memory safe su seems like a good idea.
And given su and sudo provide similar functionality, doing them together likely creates synergies and code that can be shared.
And su has to be setuid root and is pretty much mandatory and if you can exploit a bug in it you've got local privilege escalation. I don't know selinux/apparmor well but I imagine su is granted the permission to create root shells, because of course it does, so any exploit will punch through all that as well.
Sudo had a root exploit recently that wasn’t memory safety related, but the rust sun types would have prevented that too. They remove any urge to use sigils (ie negative 1 or 0 mean something special) which you can forget to check. Its easier and nicer to use rust sun types and they don’t let you forget.
A 1000 line long dependency file full of random literally whos code doing god knows what does not instill alot of confidence when I want to build and audit security critical programs.
Those are direct dependencies. The full dependency list is in Cargo.lock, which (as binjooou stated) is currently at 1013 lines.
I love Rust as a language, but one of the challenges with many projects currently written in it is that they follow the NPM model of using dozens of tiny dependencies for even trivial functionality. Luckily this seems to be limited to users of crates.io for now, and maybe things will change as the library situation matures.
> the kind of app where you want to carefully audit the code line by line
This should be much less necessary for Safe Rust. The existing C sudo needs libpcre2, and OpenSSL neither of which are small - among other dependencies.
Some of these dependencies do use unsafe Rust in places, and so it's valuable that those places should be inspected carefully (and not only for sudo) - but many do not, humantime for example is entirely safe Rust. Is it possible it has a logic error of some sort? Yes. Is it likely it somehow introduces a security hole? Not really. A C equivalent could easily introduce a critical buffer overflow, use after free or similar but that's not possible in safe Rust.
sudo doesn't strictly need OpenSSL. That dependency is part of it's log server client implementation, and it's also available for the plugin system.
I had no idea sudo even had the need for plugins.
Which raises the question, maybe there's a need for two different sudo implementations. One that provides the simplest possible implementation of the feature, and another one that provides fancy log server and plugin integrations.
For something like this, I think I would actually prefer that they copied existing code for hashing. It's simple and stable enough to avoid taking a dependency.
It's harder to package if you're using Cargo. Using the sha2 crate is one line. Copying the code into your project is a ton more work.
Ease of auditing is debatable. Using shared popular libraries gives the benefit of lots of people using them.
Plus actual code audits are very rare and of dubious value. They're mostly useful for finding out how well written the code is rather than finding bugs. For that your basically want fuzzing.
Numerous systems use sudo/su, there's tons of scripts that reply on them etc. Having a more secure version of these base tools is still a good idea, even if we should be switching to doas instead/slower than is ideal.
sudo offers many more features than doas. That's doas' strength, and why I use it myself, but it also means you can't use it in more complex use cases. It's a drop-in replacement perhaps 95% of the time or thereabouts, but for the remaining 5% sudo is your only option AFAIK.
https://news.ycombinator.com/item?id=35714347
https://news.ycombinator.com/item?id=35740863