Bugs Rust Won't Catch
13 points by PuercoPop
13 points by PuercoPop
This is a follow up to An update on rust-coreutils (discussed on /s/9p8j3s). Feel free to merge the story.
It goes over some of the common mistakes found in uutils on how the team is fixing them.
In the specific case of
--preserve-root, this works because/has no parent directory, so there’s nothing for an attacker to swap from underneath you. In the more general case of comparing two arbitrary paths for filesystem identity, however, you’d want to open both and compare their(dev, inode)pairs, the way GNU coreutils does. (Think identity, not string equality.)
I'm not sure I understand. How does fs::canonicalize fall short of (dev, inode) for path comparison? Is it subject to the same PATH_MAX limitation as realpath in glibc? Is preferring (dev, inode) done to avoid a potential symlink-based memory exhaustion attack loosely reminiscent of billion laughs leveraging how filesystems like ext4 have no limit on path length/depth? Is it something else I didn't think of? ...because I don't see how (dev, inode) comparison would prevent a TOCTTOU, given you can't ask the kernel to atomically resolve multiple paths to (dev, inode) pairs in the same instant, unless the intent was to imply but not explicitly state that one should open two FDs first, extract the (dev, inode)s from them for comparison, and then use whichever you want to operate on directly without reopening it.
Aside from not stopping to think about those potential flaws in fs::canonicalize and maybe "Resolve Inputs Before Crossing a Trust Boundary" and some nuances of "Match the Original Tool’s Behavior Exactly", all of these look like mistakes my history of burnout-inducing perfectionism would probably lead me to anticipate and avoid unless I was out-of-it enough that I'd have a lapse in judgment no matter what prior training I had.
On Unix systems, fs::canonicalize is indeed just a wrapper around realpath currently. See https://doc.rust-lang.org/1.95.0/src/std/sys/fs/unix.rs.html#2185
Who knew rewriting code with decades worth of bug fixes would reintroduces those bugs and even new ones.
I still don't get why there was a need to rewrite coreutils.
Rewriting anything in anything is a mistake every engineer must learn the hard way.
You seem to have missed the part of the article listing types of bugs that still plague GNU coreutils every year but are caught by Rust. Or that having competing implementations has benefited both projects by finding and fixing cornercases, sharing and improving a test suite, and encouraging new features. Or that it's getting harder to get contributors for projects in unsafe languages. Or that uutils can actually be used as a library. Or that uutils started with very modest ambitions and grew into what it is today because many people over many years thought it was worth it.
It's understandable to read those reports and conclude that uutils is not ready. But not seeing the need for uutils, or its potential to someday become the preferable implementation, or dogmatically rejecting any rewrite, seems... Unwise.
I've rewritten my C libraries in Rust and the results have been fantastic. No regrets.
https://gif.ski originally existed as a C program. The Rust version is much faster (I never managed to make such fine-grained multi-threading in C, I've tried). It's easier to maintain. It has better Windows support, and I don't have to curse at MSVC.
It uses pngquant that started as a C program in 1999 and had a lot of work put in it later. Rewritten in Rust still works better. I was able to make it faster and parallelize parts of the algorithm that I couldn't in OpenMP.
I still don't get why there was a need to rewrite coreutils.
There wasn't, really. uutils had a relatively humble start as a way to learn Rust back in 2013. Such rewrites are far from uncommon, I think.
Rewriting anything in anything is a mistake every engineer must learn the hard way.
Not necessarily, I think (e.g., fish, but one needs to be careful in how it's planned/executed. I think there's quite a few more ways for such a thing to go wrong than right.