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.
This commit is contained in:
parent
26286a5f8c
commit
19cb6d046a
@ -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)
|
||||
|
@ -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 {
|
||||
cName := be.EncryptName(name, iv)
|
||||
if be.longNames && len(cName) > unix.NAME_MAX {
|
||||
return be.HashLongName(cName)
|
||||
// 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
|
||||
}
|
||||
return cName
|
||||
cName := be.EncryptName(name, iv)
|
||||
if be.longNames && len(cName) > NameMax {
|
||||
return be.HashLongName(cName), nil
|
||||
}
|
||||
return cName, nil
|
||||
}
|
||||
|
||||
// Dir is like filepath.Dir but returns "" instead of ".".
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user