aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--internal/fusefrontend_reverse/reverse_longnames.go10
-rw-r--r--internal/fusefrontend_reverse/rfs.go7
-rw-r--r--internal/syscallcompat/open_nofollow.go2
-rw-r--r--internal/syscallcompat/sys_darwin.go11
-rw-r--r--internal/syscallcompat/sys_linux.go13
-rw-r--r--tests/reverse/correctness_test.go30
6 files changed, 62 insertions, 11 deletions
diff --git a/internal/fusefrontend_reverse/reverse_longnames.go b/internal/fusefrontend_reverse/reverse_longnames.go
index f826d1b..a425e64 100644
--- a/internal/fusefrontend_reverse/reverse_longnames.go
+++ b/internal/fusefrontend_reverse/reverse_longnames.go
@@ -63,9 +63,15 @@ func (rfs *ReverseFS) findLongnameParent(dir string, dirIV []byte, longname stri
if hit != "" {
return hit, nil
}
- fd, err := syscallcompat.OpenDirNofollow(rfs.args.Cipherdir, dir)
+ dirfd, err := syscallcompat.OpenDirNofollow(rfs.args.Cipherdir, filepath.Dir(dir))
if err != nil {
- tlog.Warn.Printf("findLongnameParent: opendir failed: %v\n", err)
+ tlog.Warn.Printf("findLongnameParent: OpenDirNofollow failed: %v\n", err)
+ return "", err
+ }
+ fd, err := syscallcompat.Openat(dirfd, filepath.Base(dir), syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
+ syscall.Close(dirfd)
+ if err != nil {
+ tlog.Warn.Printf("findLongnameParent: Openat failed: %v\n", err)
return "", err
}
dirEntries, err := syscallcompat.Getdents(fd)
diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go
index 4f94f3c..9ef6a94 100644
--- a/internal/fusefrontend_reverse/rfs.go
+++ b/internal/fusefrontend_reverse/rfs.go
@@ -305,7 +305,12 @@ func (rfs *ReverseFS) OpenDir(cipherPath string, context *fuse.Context) ([]fuse.
return nil, fuse.ToStatus(err)
}
// Read plaintext dir
- fd, err := syscallcompat.OpenDirNofollow(rfs.args.Cipherdir, relPath)
+ dirfd, err := syscallcompat.OpenDirNofollow(rfs.args.Cipherdir, filepath.Dir(relPath))
+ if err != nil {
+ return nil, fuse.ToStatus(err)
+ }
+ fd, err := syscallcompat.Openat(dirfd, filepath.Base(relPath), syscall.O_RDONLY|syscall.O_DIRECTORY|syscall.O_NOFOLLOW, 0)
+ syscall.Close(dirfd)
if err != nil {
return nil, fuse.ToStatus(err)
}
diff --git a/internal/syscallcompat/open_nofollow.go b/internal/syscallcompat/open_nofollow.go
index d440fc3..3953a27 100644
--- a/internal/syscallcompat/open_nofollow.go
+++ b/internal/syscallcompat/open_nofollow.go
@@ -36,7 +36,7 @@ func OpenDirNofollow(baseDir string, relPath string) (fd int, err error) {
// Walk the directory tree
var dirfd2 int
for _, name := range parts {
- dirfd2, err = Openat(dirfd, name, syscall.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_DIRECTORY, 0)
+ dirfd2, err = Openat(dirfd, name, syscall.O_RDONLY|syscall.O_NOFOLLOW|syscall.O_DIRECTORY|O_PATH, 0)
syscall.Close(dirfd)
if err != nil {
return -1, err
diff --git a/internal/syscallcompat/sys_darwin.go b/internal/syscallcompat/sys_darwin.go
index 74681db..993c229 100644
--- a/internal/syscallcompat/sys_darwin.go
+++ b/internal/syscallcompat/sys_darwin.go
@@ -9,9 +9,14 @@ import (
"github.com/hanwen/go-fuse/fuse"
)
-// O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
-// to zero there.
-const O_DIRECT = 0
+const (
+ // O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
+ // to zero there.
+ O_DIRECT = 0
+
+ // O_PATH is only defined on Linux
+ O_PATH = 0
+)
// Sorry, fallocate is not available on OSX at all and
// fcntl F_PREALLOCATE is not accessible from Go.
diff --git a/internal/syscallcompat/sys_linux.go b/internal/syscallcompat/sys_linux.go
index ed5c2a3..08483fd 100644
--- a/internal/syscallcompat/sys_linux.go
+++ b/internal/syscallcompat/sys_linux.go
@@ -12,11 +12,16 @@ import (
"github.com/rfjakob/gocryptfs/internal/tlog"
)
-const _FALLOC_FL_KEEP_SIZE = 0x01
+const (
+ _FALLOC_FL_KEEP_SIZE = 0x01
-// O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
-// to zero there.
-const O_DIRECT = syscall.O_DIRECT
+ // O_DIRECT means oncached I/O on Linux. No direct equivalent on MacOS and defined
+ // to zero there.
+ O_DIRECT = syscall.O_DIRECT
+
+ // O_PATH is only defined on Linux
+ O_PATH = unix.O_PATH
+)
var preallocWarn sync.Once
diff --git a/tests/reverse/correctness_test.go b/tests/reverse/correctness_test.go
index 34b32ea..17c4cdd 100644
--- a/tests/reverse/correctness_test.go
+++ b/tests/reverse/correctness_test.go
@@ -207,3 +207,33 @@ func TestTooLongSymlink(t *testing.T) {
err2.Err)
}
}
+
+// 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
+// the executable bit.
+func Test0100Dir(t *testing.T) {
+ dir := dirA + "/" + t.Name()
+ err := os.Mkdir(dir, 0700)
+ if err != nil {
+ t.Fatal(err)
+ }
+ file := dir + "/hello"
+ err = ioutil.WriteFile(file, []byte("hello"), 0600)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = os.Chmod(dir, 0100)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ fileReverse := dirC + "/" + t.Name() + "/hello"
+ fd, err := os.Open(fileReverse)
+ // Make sure the dir can be removed after the test is done
+ os.Chmod(dir, 0700)
+ if err != nil {
+ t.Fatal(err)
+ }
+ fd.Close()
+}