It seems like I'm probably preaching to the choir, but what really is the attack surface with coreutils? I can't imagine there have been a lot of pwns as a result of the `date` command.
Untrusted input is often stored in files. Coreutils tools are often used to operate on those files.
As an obvious example, I sometimes download files from the Internet, then run coreutils sha256sum or the like on those files to verify that they're trustworthy. That means they're untrusted at the time where I use them as input to sha256sum.
If there's an RCE in sha256sum (unlikely, but this is a thought experiment to demonstrate an attack vector), then that untrusted file can just exploit that RCE directly.
If there's a bug in sha256sum which allows a malicious file to manipulate the result, then a malicious file could potentially make itself look like a trusted file and therefore get past a security barrier.
Maybe there's no bug in sha256sum, but I need to base64 decode the file before running sha256sum on it, using the base64 tool from coreutils.
If you use your imagination, I'm sure you yourself can think up plenty more use cases where you might run a program from GNU coreutils against untrusted user input. If it helps, here's a Wikipedia article which lists all commands from GNU coreutils: https://en.wikipedia.org/wiki/GNU_Core_Utilities#Commands
EDIT: To be clear, this comment is only intended to explain what the attack surface is, not to weigh in on whether rewriting the tools in Rust improves security. One could argue that it's more likely that the freshly rewritten sha256sum from uutils has a bug than that GNU sha256sum has a bug. The statement "tools from coreutils are sometimes used to operate on untrusted input and therefore have an attack surface worth exploring" is not the same as the statement "rewriting coreutils in Rust improves security". Personally, I'm excited for the uutils stuff, but not primarily because I believe it alone will directly result in significant security improvements in Ubuntu 25.10.
It's not really a bug in uutils. The option was not implemented yet when Ubuntu decided to switch. It's known that there's no 100% compatibility and won't be for a while.
To play devil's advocate, who knows what kind of madness people are handing off to subprocess.run(["date"]) et al. They shouldn't, but I'd bet my last dollar it's out there.
You don't attack coreutils. You attack the scripts. In this case it was an update script that failed because of an incompatibility. It's not too hard at all to imagine one failing in an exploitable way.
Honestly, Rust-related hilarity aside, this project was a terrible, terrible idea. Unix shell environments have always been ad hoc and poorly tested, and anything that impacts compatibility is going to break historical code that may literally be decades old.
See also the recent insanity of GNU grep suddenly tossing an error when invoked as "fgrep". You just don't do that folks.
I think he means POSIX. Didn’t check but in some cases posix only covers some options a tool provides not all. It’s a hard lesson I learned while keeping shell scripts portable between Linux and macOS.
Yep. I was slightly incorrect in my original message, though. SUSv2 (1997) specified egrep and fgrep but marked them LEGACY. POSIX.1-2001 removed them.
The only place that that doesn't support 'grep -E' and 'grep -F' nowadays is Solaris 10. But if you are still using that you will certainly run into many other missing options.
"GNU grep implemented a change that breaks pre-existing scripts using a 46 year old API, but it's OK because the required workaround works everywhere but Solaris 10" seems like not a great statement of engineering design to me.
"GNU grep added a warning to inform you of the deprecation which happened 28 years ago, but only to stderr, and still works like you expect", does to me.
Meh. Look, it broke code. "Still works like you expect" is 100% false.
The deprecation argument is at least... arguable. It was indeed retired from POSIX. But needless deprecation is itself a smell in a situation where you can't audit all the code that uses it. Don't do that. It breaks stuff. It broke the updates in the linked article too. If you have an API, leave it there absent extremely strong arguments for its removal.
This is not a rousing endorsement of the Unix shell environment. Maybe that should be rewritten in something else too (probably not Rust, Rust is probably not a good choice for this - but something that is designed in such a way that it is easy to test would be nice!).
There's nothing about rust that makes things hard to test. Actually the embedded test framework makes it easier than C. But what really matters is the public interface of those tools and that's got an extensive test suite available. It doesn't matter which language is used internal for those tests to run.
I meant that Rust is probably not a good choice for a new shell scripting environment, not that Rust is hard to test. I was responding to the claim "Unix shell environments have always been ad hoc and poorly tested", which is a bad thing and is worth fixing in and of itself.
> This is not a rousing endorsement of the Unix shell environment.
It's surely not. The question wasn't how to rewrite the shell environment to be more "endorseable", though.
The point is that we have a half century (!) long history of writing code to this admittedly fragile environment, with no way to audit usage or even find all the existing code (literally many of the authors are retired or dead).
So... it's just not a good place to play games with "Look Ma, I rewrote /usr/bin/date and it's safe now!" Mess with your own new environments, not the ones that run the rest of the world please.
Maybe it's more important to rewrite half a century of poorly documented and specified shell scripts that are so embedded that their existence gets in way of rewriting fundamental Unix command line utilities, than it is to rewrite those utilities themselves. Any time someone makes the claim "we shouldn't touch this code, it's fragile" that state of affairs is itself bad. Our free software source code shouldn't be some poorly understood black box that we're afraid to touch for fear of breaking something, and if it is that is something we should fix.
I can certainly understand it for something like sudo or for other tools where the attack surface is larger and certain security-critical interactions are happening, but in this case it really seems like a questionable tradeoff, where the benefits in this specific case are abstract (theoretically no more possibility of any memory-safety bugs) but the costs are very concrete (incompatibility issues; and possibly other, new, non-memory-safety bugs being introduced with new code).
EDIT: Just to be clear, I'm otherwise perfectly happy that these experiments are being done, and we should all be better off for it and learn something as a result. Obviously somebody has assessed that this tradeoff has at least a decent probability of being a net positive here in some timeframe, and if others are unhappy about it then I suppose they're welcome to install another implementation of coreutils, or use a different distro, or write their own, or whatever.
I'd prefer it if all software was written in languages that made it as easy as possible to avoid bugs, including memory-safety bugs, regardless of whether it seems like it has a large attack surface or not.
I view `uutils` as a good opportunity to get rid of legacy baggage that might be used by just 0.03% of the community but has to sit there and it impedes certain feature adding or bug fixing.
F.ex. `sudo-rs` does not support most of what the normal `sudo` does... and it turned out that most people did not need most of `sudo` in the first place.
OpenBSD has a lot of new stuff throughout the codebase.
No need for adding a bloated dependency (e.g. Rust) just because you want to re-implement "yes" in a "memory-safe language" when you probably have no reasons to.