win32: keep replacement temp private until commit - #568
Open
SantanDon wants to merge 1 commit into
Open
Conversation
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.
Summary
Keep Windows replacement temporary files unreadable until the archive replacement has committed.
The named Win32 source currently opens a replacement temp with
FILE_SHARE_READ. During a normal archive rewrite, another process can therefore open the sibling temp and read newly written archive contents beforezip_close()commits the replacement.Reproduction
I tested current
mainat31eefd70f27d33a442466914f5919c84784eafd8with a 128 MiB stored entry containing a unique marker. Whilezip_close()was writing the replacement, a second process enumerated the siblingvictim.zip.*temp and requested a compatibleGENERIC_READhandle.On current code the reader succeeded 13.7 ms after temp creation and read the new marker while the writer was still running; the writer then committed normally.
Simply removing sharing is not sufficient: the current commit path closes the temp handle before
MoveFileEx(), which leaves a small close-before-rename window. A reader can win that race, read the fully written temp, and its handle can make the rename fail.Fix
Open replacement temps with
FILE_SHARE_DELETEand keep the temp handle open throughMoveFileEx(). This lets Windows rename the open temp while denying concurrent read/write opens for the temp's entire pre-commit lifetime. The handle is closed after the rename, with failure paths closing it before returning.This is atomic-replacement visibility hardening, not an ACL bypass. The temp continues to use the existing destination security descriptor when available; the change prevents principals that are already permitted by that DACL from observing the new archive state through the temporary path before the replacement commits.
Verification
ERROR_SHARING_VIOLATIONobserved, writer exit 0nihtest/CTest suite: 190Test Passed.entries, 0Test Failed.entriesgit diff --checkclean