From b23e21f61fc51ffa9c1c823778553925e1cc115e Mon Sep 17 00:00:00 2001
From: Jakob Unterwurzacher
Date: Wed, 2 Jun 2021 18:20:05 +0200
Subject: 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
---
 internal/fusefrontend/file.go | 15 ++++++++++++---
 1 file 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 {
-- 
cgit v1.2.3