summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend/fs.go14
-rw-r--r--internal/fusefrontend/fs_dir.go2
-rw-r--r--internal/fusefrontend/names.go16
-rw-r--r--tests/reverse/correctness_test.go2
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