diff options
| author | Jakob Unterwurzacher | 2019-02-17 17:05:05 +0100 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2019-02-17 17:05:05 +0100 | 
| commit | 19cb6d046aac92f44722c17ba9a371b08ca0be6a (patch) | |
| tree | c7134052a935c75ab834786a59df9529aa8495f3 | |
| parent | 26286a5f8cbd11557bc6e733741fbd3980f6d050 (diff) | |
nametransform: reject names longer than 255 chars
Looks like we allowed creating longer names by accident.
Fix that, and add a test that verifies it.
| -rw-r--r-- | internal/fusefrontend/openbackingdir.go | 12 | ||||
| -rw-r--r-- | internal/nametransform/diriv.go | 15 | ||||
| -rw-r--r-- | internal/nametransform/names.go | 5 | ||||
| -rw-r--r-- | tests/matrix/matrix_test.go | 51 | 
4 files changed, 75 insertions, 8 deletions
| diff --git a/internal/fusefrontend/openbackingdir.go b/internal/fusefrontend/openbackingdir.go index 1cca81b..e9e10db 100644 --- a/internal/fusefrontend/openbackingdir.go +++ b/internal/fusefrontend/openbackingdir.go @@ -38,7 +38,11 @@ func (fs *FS) openBackingDir(relPath string) (dirfd int, cName string, err error  			return dirfd, ".", nil  		}  		name := filepath.Base(relPath) -		cName = fs.nameTransform.EncryptAndHashName(name, iv) +		cName, err = fs.nameTransform.EncryptAndHashName(name, iv) +		if err != nil { +			syscall.Close(dirfd) +			return -1, "", err +		}  		return dirfd, cName, nil  	}  	// Open cipherdir (following symlinks) @@ -58,7 +62,11 @@ func (fs *FS) openBackingDir(relPath string) (dirfd int, cName string, err error  			syscall.Close(dirfd)  			return -1, "", err  		} -		cName = fs.nameTransform.EncryptAndHashName(name, iv) +		cName, err = fs.nameTransform.EncryptAndHashName(name, iv) +		if err != nil { +			syscall.Close(dirfd) +			return -1, "", err +		}  		// Last part? We are done.  		if i == len(parts)-1 {  			fs.dirCache.Store(dirRelPath, dirfd, iv) diff --git a/internal/nametransform/diriv.go b/internal/nametransform/diriv.go index 09e9dd5..da33aee 100644 --- a/internal/nametransform/diriv.go +++ b/internal/nametransform/diriv.go @@ -8,8 +8,6 @@ import (  	"path/filepath"  	"syscall" -	"golang.org/x/sys/unix" -  	"github.com/rfjakob/gocryptfs/internal/cryptocore"  	"github.com/rfjakob/gocryptfs/internal/syscallcompat"  	"github.com/rfjakob/gocryptfs/internal/tlog" @@ -97,12 +95,17 @@ func WriteDirIVAt(dirfd int) error {  // encryptAndHashName encrypts "name" and hashes it to a longname if it is  // too long. -func (be *NameTransform) EncryptAndHashName(name string, iv []byte) string { +// Returns ENAMETOOLONG if "name" is longer than 255 bytes. +func (be *NameTransform) EncryptAndHashName(name string, iv []byte) (string, error) { +	// Prevent the user from creating files longer than 255 chars. +	if len(name) > NameMax { +		return "", syscall.ENAMETOOLONG +	}  	cName := be.EncryptName(name, iv) -	if be.longNames && len(cName) > unix.NAME_MAX { -		return be.HashLongName(cName) +	if be.longNames && len(cName) > NameMax { +		return be.HashLongName(cName), nil  	} -	return cName +	return cName, nil  }  // Dir is like filepath.Dir but returns "" instead of ".". diff --git a/internal/nametransform/names.go b/internal/nametransform/names.go index 638a9eb..20fbede 100644 --- a/internal/nametransform/names.go +++ b/internal/nametransform/names.go @@ -12,6 +12,11 @@ import (  	"github.com/rfjakob/gocryptfs/internal/tlog"  ) +const ( +	// Like ext4, we allow at most 255 bytes for a file name. +	NameMax = 255 +) +  // NameTransform is used to transform filenames.  type NameTransform struct {  	emeCipher *eme.EMECipher diff --git a/tests/matrix/matrix_test.go b/tests/matrix/matrix_test.go index be47990..33d2ab2 100644 --- a/tests/matrix/matrix_test.go +++ b/tests/matrix/matrix_test.go @@ -377,6 +377,57 @@ func TestRename(t *testing.T) {  	test_helpers.TestRename(t, test_helpers.DefaultPlainDir)  } +// Test that names of all lengths work +func TestNameLengths(t *testing.T) { +	f, err := os.Open(test_helpers.DefaultPlainDir) +	if err != nil { +		t.Fatal(err) +	} +	entries, err := f.Readdirnames(0) +	if err != nil { +		t.Fatal(err) +	} +	f.Close() +	cnt1 := len(entries) + +	wd := test_helpers.DefaultPlainDir + "/" +	name := "x" +	for len(name) < 2000 { +		f, err := os.Create(wd + name + "x") +		if err != nil { +			break +		} +		name = name + "x" +		f.Close() +		f, err = os.Open(test_helpers.DefaultPlainDir) +		if err != nil { +			t.Fatal(err) +		} +		// In v1.7-rc2, we had a bug that allowed creation of too-long names. +		// This threw errors in like this in READDIR: +		// +		//   OpenDir ".": invalid entry "gocryptfs.longname.wrE-izsR9ciEkP7JSCFDrk_d_Nj4mQo1dGY6hjuixAU=": +		//   Could not read .name: ReadLongName: size=345 > limit=344 +		// +		entries, err = f.Readdirnames(0) +		if err != nil { +			t.Fatal(err) +		} +		f.Close() +		cnt2 := len(entries) +		if cnt2 != cnt1+1 { +			t.Fatalf("len=%d: expected %d dir entries, have %d: %v", len(name), cnt1+1, cnt2, entries) +		} +		err = syscall.Unlink(wd + name) +		if err != nil { +			t.Fatal(err) +		} +	} +	if len(name) != 255 { +		t.Errorf("maxlen=%d", len(name)) +	} +} +  func TestLongNames(t *testing.T) {  	fi, err := ioutil.ReadDir(test_helpers.DefaultCipherDir)  	if err != nil { | 
