A fast and secure tar parser for the Rust ecosystem

78 points by yossarian


abrambleninja

This is a very interesting article with great explanations and diagrams. I think the state machine diagrams really help make sense of what's going on. Thanks for sharing!

As an only tangentially related point, the post mentions:

Extracting an archive (of any format) onto disk is its own can of worms, with its own differential risks18. Another one of our early observations is that every archive implementation tends to have its own extract-to-disk implementation, with its own edge cases.

We built archive-trait to address that. archive-trait exposes Archive and ArchiveBuilder traits (along with associated types and machinery) that allow any format to expose uniform APIs for reading and creating archives. We then built archive-trait's own filesystem extraction on top of cap-std, giving us the ability to "anchor" extraction into a single directory and avoid a large class of link and path traversal footguns.

This reminds me of an exploit that I learned about that I found quite clever. It was used to get the ability to add unauthorized 3rd party apps to a Kindle (the one I'm thinking of is the Kindle Touch but maybe applied to others as well). My recollection of it off the top of my head is as follows: system updates came packaged as a compressed tar file. The system would untar the update, then find a signature inside of the archive to decide if it was an approved software update based off of the signature matching a public key that was stored in something like /etc/authorized_keys. If the public key matched, then it would run the update; otherwise, it would delete it. Well, turns out there was a bug in the untar program, and you could craft a malicious tar file that had path (along the lines of) ../../../etc/authorized_keys, and when this was untarred it would clobber the original list of public keys, thus allowing a provided update payload to run.

It's a somewhat different class of vulnerability in tar files than the OP was discussing, but I guess it just goes to show that there's a lot that goes into these things to keep them secure.

andyc

Hm very interesting. This seems like a tight rope to walk, since compatibility and avoiding parser differentials are fundamentally opposed (i.e. more features supported is more potential differences).

Without knowing much about Python packaging, I wonder if there are something like 100K or 500K source tarballs in PyPI? If so, I wonder what the "minimum tar" necessary to parse those is. It seems like potentially a more bounded problem - parse the things that are in PyPI.

And then maybe reject input at PyPI upload time (although I understand why this is hard in a social sense)

I asked Gemini and practically speaking the "writers" include GNU tar, OS X tar which is more like BSD, Python's tarfile module, and Go's tar module. All of them use SOME extensions, e.g. for long filenames, but I also wonder if the union of all features they emit is meaningfully smaller than "all tar extensions" !


Also reminding myself that this post also has a bunch of background on the various tar format extensions, in the context of OCI: https://www.cyphar.com/blog/post/20190121-ociv2-images-i-tar/

I also wonder if tar files that appear in practice in Docker/OCI are of different dialects than PyPI, or it's all basically the same set of tools creating them.