summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend/openbackingdir.go12
-rw-r--r--internal/nametransform/diriv.go15
-rw-r--r--internal/nametransform/names.go5
-rw-r--r--tests/matrix/matrix_test.go51
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 {