shred: correctness and GNU-compatibility fixes#11513
Draft
can1357 wants to merge 7 commits intouutils:mainfrom
Draft
shred: correctness and GNU-compatibility fixes#11513can1357 wants to merge 7 commits intouutils:mainfrom
can1357 wants to merge 7 commits intouutils:mainfrom
Conversation
|
GNU testsuite comparison: |
Merging this PR will degrade performance by 4.63%
Performance Changes
Comparing Footnotes
|
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.
This PR fixes a cluster of bugs found while auditing
shred. They break down into TOCTOU races, dir sync issues, missing truncate, degraded-media handling, direct I/O, and an unchecked close(fd).TOCTOU + incorrect file-type gate
wipe_fileperformspath.is_file()and then opens the path in a separate syscall. That creates a TOCTOU window (e.g., symlink/target swap between check and open). It also rejects non-regular files up front, including block/character devices, which diverges from GNUshredbehavior.Non-atomic rename in
wipe_namewipe_namedoesnew_path.exists()beforefs::rename.Incorrect fsync target for metadata durability
wipe_namesyncs the renamed file descriptor, but rename durability is a directory metadata concern. Without syncing the parent directory, a crash can resurrect older directory entries.do_removeunlinks without syncing the parent directory afterward at all, so directory-entry deletion is not crash-durable either.Missing truncate-before-remove
With
--remove, the code proceeds to rename/unlink without first truncating to zero. If removal fails partway, the remaining file can retain original length metadata and delayed-deallocation artifacts.No bad-sector continuation on EIO
do_passusesfile.write_all(block)?; anyEIOaborts the pass immediately. On degraded media, sectors after the first I/O failure are left unwiped.No direct-I/O path
Writes are fully buffered through page cache. On large targets this causes cache pollution and can leave plaintext temporarily resident in cache.
Unchecked close before remove path
The writable fd is not closed (and checked) before entering name-wipe/unlink. On backends that report delayed write errors at
close(e.g., NFS/FUSE), removal can proceed even though overwrite was not durably successful.I apologize for the big PR, but it included a few reworks. Changes should be now mostly atomically scoped per-commit though.