diff options
| author | Jakob Unterwurzacher | 2021-06-02 18:20:05 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2021-06-02 18:20:05 +0200 | 
| commit | b23e21f61fc51ffa9c1c823778553925e1cc115e (patch) | |
| tree | 14febe8934716ae8589b2495636a5dceec935180 | |
| parent | 04858ddd222bbf7156f33f99cfb293a9b1e15ec8 (diff) | |
fusefrontend: catch ReadAt integer overflow
Discovered by xfstests generic/564 .
Failure was:
generic/564	- output mismatch (see /opt/fuse-xfstests/results//generic/564.out.bad)
    --- tests/generic/564.out	2021-05-08 21:11:05.307395966 +0200
    +++ /opt/fuse-xfstests/results//generic/564.out.bad	2021-05-19 19:01:16.912888879 +0200
    @@ -31,7 +31,7 @@
     source range beyond 8TiB returns 0
     destination range beyond 8TiB returns EFBIG
    -copy_range: File too large
    +copy_range: Function not implemented
| -rw-r--r-- | internal/fusefrontend/file.go | 15 | 
1 files changed, 12 insertions, 3 deletions
| diff --git a/internal/fusefrontend/file.go b/internal/fusefrontend/file.go index 33a3cbe..cbf78e9 100644 --- a/internal/fusefrontend/file.go +++ b/internal/fusefrontend/file.go @@ -9,6 +9,7 @@ import (  	"fmt"  	"io"  	"log" +	"math"  	"os"  	"sync"  	"syscall" @@ -178,6 +179,10 @@ func (f *File) doRead(dst []byte, off uint64, length uint64) ([]byte, syscall.Er  	// Read the backing ciphertext in one go  	blocks := f.contentEnc.ExplodePlainRange(off, length)  	alignedOffset, alignedLength := blocks[0].JointCiphertextRange(blocks) +	// f.fd.ReadAt takes an int64! +	if alignedOffset > math.MaxInt64 { +		return nil, syscall.EFBIG +	}  	skip := blocks[0].Skip  	tlog.Debug.Printf("doRead: off=%d len=%d -> off=%d len=%d skip=%d\n",  		off, length, alignedOffset, alignedLength, skip) @@ -320,9 +325,13 @@ func (f *File) doWrite(data []byte, off int64) (uint32, syscall.Errno) {  	// Preallocate so we cannot run out of space in the middle of the write.  	// This prevents partially written (=corrupt) blocks.  	var err error -	cOff := int64(blocks[0].BlockCipherOff()) +	cOff := blocks[0].BlockCipherOff() +	// f.fd.WriteAt & syscallcompat.EnospcPrealloc take int64 offsets! +	if cOff > math.MaxInt64 { +		return 0, syscall.EFBIG +	}  	if !f.rootNode.args.NoPrealloc { -		err = syscallcompat.EnospcPrealloc(f.intFd(), cOff, int64(len(ciphertext))) +		err = syscallcompat.EnospcPrealloc(f.intFd(), int64(cOff), int64(len(ciphertext)))  		if err != nil {  			if !syscallcompat.IsENOSPC(err) {  				tlog.Warn.Printf("ino%d fh%d: doWrite: prealloc failed: %v", f.qIno.Ino, f.intFd(), err) @@ -339,7 +348,7 @@ func (f *File) doWrite(data []byte, off int64) (uint32, syscall.Errno) {  		}  	}  	// Write -	_, err = f.fd.WriteAt(ciphertext, cOff) +	_, err = f.fd.WriteAt(ciphertext, int64(cOff))  	// Return memory to CReqPool  	f.rootNode.contentEnc.CReqPool.Put(ciphertext)  	if err != nil { | 
