diff options
| -rw-r--r-- | internal/fusefrontend_reverse/reverse_longnames.go | 10 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/rfs.go | 7 | ||||
| -rw-r--r-- | internal/syscallcompat/open_nofollow.go | 2 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_darwin.go | 11 | ||||
| -rw-r--r-- | internal/syscallcompat/sys_linux.go | 13 | ||||
| -rw-r--r-- | tests/reverse/correctness_test.go | 30 | 
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() +} | 
