From e827763f2e6226d9f5778d56c28270264950c0f5 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Tue, 23 May 2017 20:46:24 +0200 Subject: nametransform: harden name decryption against invalid input This fixes a few issues I have found reviewing the code: 1) Limit the amount of data ReadLongName() will read. Previously, you could send gocryptfs into out-of-memory by symlinking gocryptfs.diriv to /dev/zero. 2) Handle the empty input case in unPad16() by returning an error. Previously, it would panic with an out-of-bounds array read. It is unclear to me if this could actually be triggered. 3) Reject empty names after base64-decoding in DecryptName(). An empty name crashes emeCipher.Decrypt(). It is unclear to me if B64.DecodeString() can actually return a non-error empty result, but let's guard against it anyway. --- internal/nametransform/longnames.go | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'internal/nametransform/longnames.go') diff --git a/internal/nametransform/longnames.go b/internal/nametransform/longnames.go index 54095a4..8af191d 100644 --- a/internal/nametransform/longnames.go +++ b/internal/nametransform/longnames.go @@ -2,7 +2,8 @@ package nametransform import ( "crypto/sha256" - "io/ioutil" + "fmt" + "io" "os" "path/filepath" "strings" @@ -62,13 +63,29 @@ func IsLongContent(cName string) bool { return NameType(cName) == LongNameContent } -// ReadLongName - read path.name +// ReadLongName - read "$path.name" func ReadLongName(path string) (string, error) { - content, err := ioutil.ReadFile(path + LongNameSuffix) + path += LongNameSuffix + fd, err := os.Open(path) if err != nil { - tlog.Warn.Printf("ReadLongName: %v", err) + return "", err } - return string(content), err + defer fd.Close() + // 256 (=255 padded to 16) bytes base64-encoded take 344 bytes: "AAAAAAA...AAA==" + lim := 344 + // Allocate a bigger buffer so we see whether the file is too big + buf := make([]byte, lim+1) + n, err := fd.ReadAt(buf, 0) + if err != nil && err != io.EOF { + return "", err + } + if n == 0 { + return "", fmt.Errorf("ReadLongName: empty file") + } + if n > lim { + return "", fmt.Errorf("ReadLongName: size=%d > limit=%d", n, lim) + } + return string(buf[0:n]), nil } // DeleteLongName deletes "hashName.name". -- cgit v1.2.3