main: refuse to write the output into the input file - #428
Open
woahwhattheheck wants to merge 3 commits into
Open
main: refuse to write the output into the input file#428woahwhattheheck wants to merge 3 commits into
woahwhattheheck wants to merge 3 commits into
Conversation
"scrypt enc secret.txt secret.txt" opens secret.txt for reading, reads a passphrase, then opens the same path with fopen(..., "wb"), which truncates it. scryptenc_file() then reads from the now-empty file, gets EOF on the first fread(), writes a valid 128-byte scrypt file containing an encryption of no data, and returns SCRYPT_OK; scrypt exits 0. The file the user asked to encrypt is gone, with no error and nothing to indicate that anything went wrong. "scrypt dec f f" destroys the ciphertext the same way, and both are also reachable with the input on stdin, e.g. "scrypt enc - f < f". Compare the open input file and the output path with fstat() and stat() before opening the output, and exit with an error if they are the same regular file. Devices are excluded: opening /dev/null for writing discards nothing. The check runs before the passphrase is read, so the user is not asked to type a passphrase for a command which cannot succeed. Add tests/12-same-file.sh, and document the restriction in scrypt.1.
This was referenced Sep 6, 2026
The previous commit was uploaded through the GitHub API by a helper which dropped the final newline of every text file it sent. Rewrite those files with their trailing newline intact; no other change.
Add the authored static-alias and independent-file regression coverage to the existing test scenario. Preserve the application implementation and existing upstream submission.
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 #427.
scrypt enc secret.txt secret.txtopenssecret.txtfor reading, reads apassphrase, then opens the same path with
fopen(..., "wb")— which truncatesit. Nothing has been read from the input yet, so the first
fread()inscryptenc_file()returns 0,ferror()is false, and the empty read isindistinguishable from a legitimately empty file.
scryptenc_file()writes theheader and HMAC, returns
SCRYPT_OK, andscryptexits 0. The user's file isreplaced by a 128-byte encryption of nothing, silently.
scrypt dec f floses the ciphertext the same way, and both are reachable withthe input on stdin (
scrypt enc - f < f).The change
same_file()compares the already-open input against the output path withfstat()/stat()and reports whether they are the same regular file:fstat(fileno(infile))rather thanstat(infilename)so that thestdin cases are covered too, and so that symlinks, hard links and different
spellings of the same path are all handled.
/dev/nullfor writing discards nothing, so
scrypt enc /dev/null /dev/nullkeepsworking.
statfails the answer is "different", so the normal case wherethe output file does not exist yet costs one failed
stat()and nothingelse.
The check sits immediately after the input is opened and before the
passphrase is read, so the user is not asked to type a passphrase for a command
that cannot succeed. It jumps to the existing
err1label, which closes theinput; no output file is created.
fileno()is already used inlibcperciva/util/readpass.cand<sys/types.h>in
lib-platform/util/memlimit.c, so this adds no new portability burden.Also
tests/12-same-file.shcoversencanddecwith the same file, assertsexit status 1, the error message, and that the input is byte-for-byte
unchanged; plus a check that encrypting to a different file still works, so
a false positive in
same_file()would be caught.scrypt.1documents the restriction.Note on the test number
The test is numbered
12rather than11so that it does not collide withtests/11-info.shfrom #426. The ordering works whichever of the two landsfirst; the only overlap is the adjacent line each adds to
EXTRA_DISTinMakefile.am. Happy to renumber if you would rather not take #426.