diff options
-rw-r--r-- | internal/fusefrontend/fs.go | 14 | ||||
-rw-r--r-- | internal/fusefrontend/fs_dir.go | 2 | ||||
-rw-r--r-- | internal/fusefrontend/names.go | 16 | ||||
-rw-r--r-- | tests/reverse/correctness_test.go | 2 |
4 files changed, 19 insertions, 15 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go index 45b5b40..d68939b 100644 --- a/internal/fusefrontend/fs.go +++ b/internal/fusefrontend/fs.go @@ -250,7 +250,7 @@ func (fs *FS) Chmod(path string, mode uint32, context *fuse.Context) (code fuse. if fs.isFiltered(path) { return fuse.EPERM } - dirfd, cName, err := fs.openBackingPath(path) + dirfd, cName, err := fs.openBackingDir(path) if err != nil { return fuse.ToStatus(err) } @@ -266,7 +266,7 @@ func (fs *FS) Chown(path string, uid uint32, gid uint32, context *fuse.Context) if fs.isFiltered(path) { return fuse.EPERM } - dirfd, cName, err := fs.openBackingPath(path) + dirfd, cName, err := fs.openBackingDir(path) if err != nil { return fuse.ToStatus(err) } @@ -291,7 +291,7 @@ func (fs *FS) Mknod(path string, mode uint32, dev uint32, context *fuse.Context) if fs.isFiltered(path) { return fuse.EPERM } - dirfd, cName, err := fs.openBackingPath(path) + dirfd, cName, err := fs.openBackingDir(path) if err != nil { return fuse.ToStatus(err) } @@ -409,7 +409,7 @@ func (fs *FS) Unlink(path string, context *fuse.Context) (code fuse.Status) { if fs.isFiltered(path) { return fuse.EPERM } - dirfd, cName, err := fs.openBackingPath(path) + dirfd, cName, err := fs.openBackingDir(path) if err != nil { return fuse.ToStatus(err) } @@ -447,7 +447,7 @@ func (fs *FS) Symlink(target string, linkName string, context *fuse.Context) (co if fs.isFiltered(linkName) { return fuse.EPERM } - dirfd, cName, err := fs.openBackingPath(linkName) + dirfd, cName, err := fs.openBackingDir(linkName) if err != nil { return fuse.ToStatus(err) } @@ -579,12 +579,12 @@ func (fs *FS) Link(oldPath string, newPath string, context *fuse.Context) (code if fs.isFiltered(newPath) { return fuse.EPERM } - oldDirFd, cOldName, err := fs.openBackingPath(oldPath) + oldDirFd, cOldName, err := fs.openBackingDir(oldPath) if err != nil { return fuse.ToStatus(err) } defer oldDirFd.Close() - newDirFd, cNewName, err := fs.openBackingPath(newPath) + newDirFd, cNewName, err := fs.openBackingDir(newPath) if err != nil { return fuse.ToStatus(err) } diff --git a/internal/fusefrontend/fs_dir.go b/internal/fusefrontend/fs_dir.go index b7bc790..b9266dd 100644 --- a/internal/fusefrontend/fs_dir.go +++ b/internal/fusefrontend/fs_dir.go @@ -54,7 +54,7 @@ func (fs *FS) Mkdir(newPath string, mode uint32, context *fuse.Context) (code fu if fs.isFiltered(newPath) { return fuse.EPERM } - dirfd, cName, err := fs.openBackingPath(newPath) + dirfd, cName, err := fs.openBackingDir(newPath) if err != nil { return fuse.ToStatus(err) } diff --git a/internal/fusefrontend/names.go b/internal/fusefrontend/names.go index 9be2623..d7fbdce 100644 --- a/internal/fusefrontend/names.go +++ b/internal/fusefrontend/names.go @@ -7,6 +7,7 @@ import ( "path/filepath" "github.com/rfjakob/gocryptfs/internal/configfile" + "github.com/rfjakob/gocryptfs/internal/syscallcompat" "github.com/rfjakob/gocryptfs/internal/tlog" ) @@ -40,18 +41,21 @@ func (fs *FS) getBackingPath(relPath string) (string, error) { return cAbsPath, nil } -// openBackingPath - get the absolute encrypted path of the backing file -// and open the corresponding directory -func (fs *FS) openBackingPath(relPath string) (*os.File, string, error) { - cPath, err := fs.getBackingPath(relPath) +// openBackingDir opens the parent ciphertext directory of plaintext path +// "relPath" and returns the dirfd and the encrypted basename. +// The caller should then use Openat(dirfd, cName, ...) and friends. +// openBackingDir is secure against symlink races. +func (fs *FS) openBackingDir(relPath string) (*os.File, string, error) { + cRelPath, err := fs.encryptPath(relPath) if err != nil { return nil, "", err } - dirfd, err := os.Open(filepath.Dir(cPath)) + // Open parent dir + dirfd, err := syscallcompat.OpenDirNofollow(fs.args.Cipherdir, filepath.Dir(cRelPath)) if err != nil { return nil, "", err } - return dirfd, filepath.Base(cPath), nil + return os.NewFile(uintptr(dirfd), cRelPath), filepath.Base(cRelPath), nil } // encryptPath - encrypt relative plaintext path diff --git a/tests/reverse/correctness_test.go b/tests/reverse/correctness_test.go index bb93316..62e3bbc 100644 --- a/tests/reverse/correctness_test.go +++ b/tests/reverse/correctness_test.go @@ -210,7 +210,7 @@ func TestTooLongSymlink(t *testing.T) { // Test that we can traverse a directory with 0100 permissions // (execute but no read). This used to be a problem as OpenDirNofollow opened -// all directory in the path with O_RDONLY. Now it uses O_PATH, which only needs +// all directories in the path with O_RDONLY. Now it uses O_PATH, which only needs // the executable bit. func Test0100Dir(t *testing.T) { // Note: t.Name() is not available before in Go 1.8 |