fix(cp): don't delete dest before same-file check with --remove-destination#13158
Open
koopatroopa787 wants to merge 1 commit into
Open
fix(cp): don't delete dest before same-file check with --remove-destination#13158koopatroopa787 wants to merge 1 commit into
koopatroopa787 wants to merge 1 commit into
Conversation
…nation cp --remove-destination a ./a unlinked the file before detecting that source and destination were the same path, destroying the only copy of the data. The "source != dest" guard only compared the raw Path values, so differently-spelled references to the same directory entry slipped through. Compare canonicalized paths instead, so the deletion still happens for the legitimate case of two distinct directory entries hard-linked to the same file (which must keep working for --remove-destination), but is skipped when source and dest are actually the same entry. Fixes GHSA-9p9p-xh9v-6fvx
|
GNU testsuite comparison: |
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 #13144 (GHSA-9p9p-xh9v-6fvx).
Bug
cp --remove-destination a ./adeletes the file before discovering thatsource and destination refer to the same data, destroying it. GNU cp
refuses with
cp: 'a' and './a' are the same fileand leaves the fileintact.
Root cause
In
copy_file, the block that removesdestahead of time to let--remove-destinationrecreate hard-linked destinations usedsource != dest(a rawPathcomparison) as the guard against deleting the sourceitself:
"a"and"./a"are differentPathvalues but the exact samedirectory entry, so the guard doesn't catch this case and the file gets
unlinked before the later same-file check (in
handle_existing_dest)ever runs.
Fix
Compare canonicalized paths instead of the raw
Paths. This still allowsdeletion for the legitimate case this block exists for — two distinct
directory entries that are hard-linked to each other (e.g.
cp --remove-destination file hardlink, covered bytest_remove_destination_with_destination_being_a_hardlink_to_source) —but skips it when source and dest are actually the same entry, letting
the existing "same file" error fire instead.
Testing
Added
test_remove_destination_same_path_does_not_destroy_file(cross-platform) reproducing the exact GHSA repro. Ran the full
cptestsuite (159 tests) with no regressions, plus
cargo clippy -D warningsand
cargo fmt --check.