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/names.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'internal/nametransform/names.go') diff --git a/internal/nametransform/names.go b/internal/nametransform/names.go index c96f7ce..3447583 100644 --- a/internal/nametransform/names.go +++ b/internal/nametransform/names.go @@ -42,6 +42,10 @@ func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error if err != nil { return "", err } + if len(bin) == 0 { + tlog.Warn.Printf("DecryptName: empty input") + return "", syscall.EBADMSG + } if len(bin)%aes.BlockSize != 0 { tlog.Debug.Printf("DecryptName %q: decoded length %d is not a multiple of 16", cipherName, len(bin)) return "", syscall.EBADMSG @@ -49,14 +53,14 @@ func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error bin = n.emeCipher.Decrypt(iv, bin) bin, err = unPad16(bin) if err != nil { - tlog.Debug.Printf("DecryptName: unPad16 error: %v", err) + tlog.Debug.Printf("DecryptName: unPad16 error detail: %v", err) // unPad16 returns detailed errors including the position of the // incorrect bytes. Kill the padding oracle by lumping everything into // a generic error. return "", syscall.EBADMSG } // A name can never contain a null byte or "/". Make sure we never return those - // to the user, even when we read a corrupted (or fuzzed) filesystem. + // to the kernel, even when we read a corrupted (or fuzzed) filesystem. if bytes.Contains(bin, []byte{0}) || bytes.Contains(bin, []byte("/")) { return "", syscall.EBADMSG } -- cgit v1.2.3