fix(macos): restore directory deferral lost in the AppleDouble extractor - #523
Merged
Conversation
#506 replaced Archive::unpack with a per-entry unpack_in loop so AppleDouble "._" members could be skipped. That loop reproduced the iteration but not the two things unpack does around it. Directories are now applied last, reverse-sorted by path, the way Archive::_unpack does (tar-rs#242): a directory carries its own mode, so creating it inline in archive order means a 0o555 member exists before its contents are written and the next file inside it fails with EACCES. On a runtime pack that contains one, first-run setup dies with no fallback. `ditto` and `tar` both record such modes faithfully, so this was reachable. `destination` is canonicalized before the loop again, which on Windows supplies the \\?\ prefix so member paths over 260 characters still extract. Traversal protection was never affected and is unchanged: unpack_in rejects ParentDir components, strips RootDir/Prefix, and canonicalizes against dst on every entry, so zip-slip, absolute members and symlink escapes stay blocked. This was a robustness regression, not a security one. Deferring costs nothing on a streaming archive: directory entries carry no data, so only their metadata is applied in the second pass. The new test builds a .tar.zst whose directory member is 0o555 and whose file member follows it, which is the order that broke. Verified it fails against inline creation and passes with the deferral. Refs #508
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #508. Follow-up to #506 -- a regression introduced by that PR.
#506 replaced
Archive::unpackwith a per-entryunpack_inloop so AppleDouble._members could be skipped. The loop reproduced the iteration but not the two thingsunpackdoes around it.1. Directory deferral
Archive::_unpack(tar-0.4.45archive.rs:245-265):A directory carries its own mode. Created inline in archive order, a
0o555member exists before its contents are written, and the next file inside it failsFile::createwith EACCES --unpack_without_apple_doublereturnsErrand first-run setup dies with no fallback.dittoandtarboth record such modes faithfully, so this was reachable, not theoretical.Deferring costs nothing on a streaming archive: directory entries carry no data, so the second pass applies metadata only.
2.
destinationcanonicalizationRestored before the loop. On Windows this supplies the
\\?\extended-length prefix so member paths over 260 characters still extract.Not affected: traversal protection
unpack_inrejectsParentDircomponents, stripsRootDir/Prefix, and callsvalidate_inside_dst-- which canonicalizes on every entry -- so zip-slip, absolute members and symlink escapes were blocked throughout. This was a robustness regression, not a security one.Impact
Latent on shipped artifacts. The published 0.16.0 pack has no restrictive directory members: extracting it end to end produced 27,797 files and 0 sidecars. Windows takes the zip path for updates, so the long-path loss was theoretical there. Fixed because the next pack is not guaranteed to be as forgiving.
Verification
New test
extract_tar_archive_survives_a_read_only_directory_memberbuilds a.tar.zstwhose0o555directory member precedes its file member -- the order that broke -- and asserts the file extracts and the directory keeps its archived mode.Confirmed the test is not vacuous: with directories created inline it fails; with deferral it passes.