ext4/dmverity: use io.ReadFull when reading the super block and root hash - #2888
Open
Nilesh Patil (nileshpatil6) wants to merge 1 commit into
Open
ext4/dmverity: use io.ReadFull when reading the super block and root hash#2888Nilesh Patil (nileshpatil6) wants to merge 1 commit into
Nilesh Patil (nileshpatil6) wants to merge 1 commit into
Conversation
…hash
ReadDMVerityInfoReader takes an io.Reader and calls r.Read(block) once
per block, treating a return of fewer than blockSize bytes as a failure:
if s, err := r.Read(block); err != nil || s != blockSize {
io.Reader explicitly permits a Read to return fewer bytes than requested
without that being an error, so a hash device that is entirely valid
fails to parse whenever it arrives through a reader that returns short
reads. Only an *os.File happens to satisfy the current assumption.
Use io.ReadFull for both blocks. A genuinely truncated device still
reports the same errors: io.ReadFull returns io.EOF when nothing could
be read and io.ErrUnexpectedEOF on a partial block, so the existing
"unexpected bytes read" message and the ErrSuperBlockReadFailure and
ErrRootHashReadFailure wrapping are preserved.
Adds a test that feeds the same bytes through a reader returning one
byte per call and checks the root digest matches the whole-block read.
Signed-off-by: nileshpatil6 <technil6436@gmail.com>
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.
The bug
ReadDMVerityInfoReaderaccepts anio.Readerbut reads each block with a singleReadcall and treats a short return as a failure:The same pattern is repeated for the root hash block.
io.Readerexplicitly allows aReadto return fewer bytes than requested without that being an error:So a hash device that is completely valid fails to parse whenever it arrives through a reader that returns short reads. It happens to work today only because the exported
ReadDMVerityInfopath hands it an*os.File. Any other reader, for example one wrapping a network stream or a tar entry, can fail:ext4/dmverityis imported byext4/tar2ext4,internal/verity,internal/guest/storage/devicemapperandtest/internal/layers, andReadDMVerityInfoReaderis exported, so external callers can pass any reader they like.The change
Use
io.ReadFullfor both blocks.Error behaviour for genuinely truncated input is preserved:
io.ReadFullreturnsio.EOFwhen nothing could be read andio.ErrUnexpectedEOFon a partial block, so the existingunexpected bytes readmessage and theErrSuperBlockReadFailure/ErrRootHashReadFailurewrapping still apply. The existingTestInvalidReadEOFandTestInvalidReadNotEnoughBytespass unchanged.Testing
Added
TestReadDMVerityInfoReaderShortReads, which feeds identical bytes through a reader returning one byte perReadand compares the root digest against a whole-block read.Without the change:
With it, the whole package passes:
gofmt -l ext4/dmverity/andgo vet ./ext4/dmverity/are both clean. Commit is signed off per the DCO requirement.Separate issue in the same file, not fixed here
While testing this I also found that
MerkleTree(r io.Reader)never terminates on an empty reader: the inner loop breaks withnextLevel.Len() == 0,0 % blockSize == 0so no padding is appended, and the only loop exit isnextLevel.Len() == blockSize, which is never reached. Each pass allocates a fresh 1 MiBbufio.NewReaderSize, so it grows memory until the process dies rather than spinning harmlessly. No in-repo caller can currently pass zero bytes, sinceConvertTarToExt4always emits a non-empty superblock, so this only affects external callers of the exported API. Happy to send that as a separate PR if you would like it fixed.