chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
Release files are read only by a hash that is a SHA-256
Merged Approved
This adds release::valid_sha256 (exactly 64 lowercase hex digits) and makes Records::fetch refuse any other hash before it builds a path. serve answers 502 without touching the disk.
I checked the points that matter:
- Both holes are closed. The check runs before
self.kept.join(hash)and before the.{sha256}.{n}temp name. Both uses read the same validatedhash, so the read and the write paths are covered. - No other path uses a record's hash.
kept_diris used only byreleases.rsand byoci.rs, and the OCI side builds its file entries from a hash it measured itself. Thesha256: name.into()entries in theoci.rstests only go intoStaged, never intofetch. The.sha256text and the etag only print the value and build no path. - Real hashes still work.
release::sha256formats with{:x}, which is lowercase 64-digit hex, so the existing release tests are unaffected. - The new test is valid. The padded
../../../../etc/passwdvalue is 64 characters long, so it fails on the hex check and not on length. It shows the new check is what refuses the value. - Changeset.
crates/knotless/srcchanges and the body hasChangeset: noneon its own line. That is reasonable, since the change is server-side.
The test, check and e2e runs were still queued when I looked. The pull needs them to pass, and I'm not withholding approval on them.
All checks have passed
8 passed, 2 skipped
Merged as 383d652
What changes
knotless-serve reads a release's file only when the file's
sha256in the release record is 64 lowercase hex digits. Otherwise it answers 502 without touching the disk.knotless::release::valid_sha256is the check.Why
A release's files are kept under the cache by their hash, as
kept.join(sha256), and the file is fetched into.{sha256}.{n}beside it. The hash comes from a record the repository's owner wrote, and nothing checked it.../../../../etc/passwd, padded to 64 characters, madetry_existstrue for that path, so serve streamed the host's file back as the release's../../xwrote the fetch's temporary file outside the cache.The review of the pages serving pull found this in its copy of the code, and that copy is fixed there. This is the same fix for releases, which are live now.
The check is at the one place a hash becomes a path. The OCI registry names what it keeps by the hash it measured itself, so it is not affected.
How it was checked
A unit test in
releases.rsrefuses a traversal hash before any path is built. The existing release tests still read files by their real hashes. CI builds and runs it.Shortcomings
A release with such a file is still listed. Only reading the file is refused.
Changeset: none
🤖 Generated with Claude Code