diff options
| -rw-r--r-- | internal/fusefrontend/fs_dir.go | 15 | ||||
| -rw-r--r-- | internal/nametransform/names.go | 18 | 
2 files changed, 19 insertions, 14 deletions
| diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go index 05cea75..7d1e3ef 100644 --- a/internal/fusefrontend/fs_dir.go +++ b/internal/fusefrontend/fs_dir.go @@ -291,8 +291,8 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f  		if isLong == nametransform.LongNameContent {  			cNameLong, err := nametransform.ReadLongName(filepath.Join(cDirAbsPath, cName))  			if err != nil { -				tlog.Warn.Printf("Skipping entry %q in dir %q: Could not read .name: %v", -					cName, cDirName, err) +				tlog.Warn.Printf("OpenDir %q: invalid entry %q: Could not read .name: %v", +					cDirName, cName, err)  				errorCount++  				continue  			} @@ -304,12 +304,13 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f  		name, err := fs.nameTransform.DecryptName(cName, cachedIV)  		if err != nil { -			tlog.Warn.Printf("Skipping entry %q in dir %q: %s", -				cName, cDirName, err) +			tlog.Warn.Printf("OpenDir %q: invalid entry %q: %v", +				cDirName, cName, err)  			errorCount++  			continue  		} - +		// Override the ciphertext name with the plaintext name but reuse the rest +		// of the structure  		cipherEntries[i].Name = name  		plain = append(plain, cipherEntries[i])  	} @@ -317,8 +318,8 @@ func (fs *FS) OpenDir(dirName string, context *fuse.Context) ([]fuse.DirEntry, f  	if errorCount > 0 && len(plain) == 0 {  		// Don't let the user stare on an empty directory. Report that things went  		// wrong. -		tlog.Warn.Printf("All %d entries in directory %q were invalid, returning EIO", -			errorCount, cDirName) +		tlog.Warn.Printf("OpenDir %q: all %d entries were invalid, returning EIO", +			cDirName, errorCount)  		status = fuse.EIO  	} diff --git a/internal/nametransform/names.go b/internal/nametransform/names.go index 71c8cd3..c96f7ce 100644 --- a/internal/nametransform/names.go +++ b/internal/nametransform/names.go @@ -2,6 +2,7 @@  package nametransform  import ( +	"bytes"  	"crypto/aes"  	"encoding/base64"  	"syscall" @@ -34,10 +35,8 @@ func New(e *eme.EMECipher, longNames bool, raw64 bool) *NameTransform {  	}  } -// DecryptName - decrypt base64-encoded encrypted filename "cipherName" -// -// This function is exported because it allows for a very efficient readdir -// implementation (read IV once, decrypt all names using this function). +// DecryptName decrypts a base64-encoded encrypted filename "cipherName" using the +// initialization vector "iv".  func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error) {  	bin, err := n.B64.DecodeString(cipherName)  	if err != nil { @@ -45,16 +44,21 @@ func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error  	}  	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.EINVAL +		return "", syscall.EBADMSG  	}  	bin = n.emeCipher.Decrypt(iv, bin)  	bin, err = unPad16(bin)  	if err != nil { -		tlog.Debug.Printf("pad16 error detail: %v", err) +		tlog.Debug.Printf("DecryptName: unPad16 error: %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.EINVAL +		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. +	if bytes.Contains(bin, []byte{0}) || bytes.Contains(bin, []byte("/")) { +		return "", syscall.EBADMSG  	}  	plain := string(bin)  	return plain, err | 
