summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2018-11-04 22:01:18 +0100
committerJakob Unterwurzacher2019-01-01 16:24:25 +0100
commit4fae240153a5300b7108bf5c2de2b6581c8ee7fd (patch)
tree383ae37643dbec97ae786358ad22488f7eb351d0
parent21f1f858b9bebb20fdb9bb3f99189279bb6c6976 (diff)
fusefrontend: make Readlink() symlink-safe
Now symlink-safe through Readlinkat().
-rw-r--r--internal/fusefrontend/fs.go14
-rw-r--r--internal/syscallcompat/sys_common.go6
2 files changed, 11 insertions, 9 deletions
diff --git a/internal/fusefrontend/fs.go b/internal/fusefrontend/fs.go
index a301231..022fd5c 100644
--- a/internal/fusefrontend/fs.go
+++ b/internal/fusefrontend/fs.go
@@ -377,6 +377,8 @@ func (fs *FS) StatFs(path string) *fuse.StatfsOut {
// decryptSymlinkTarget: "cData64" is base64-decoded and decrypted
// like file contents (GCM).
// The empty string decrypts to the empty string.
+//
+// This function does not do any I/O and is hence symlink-safe.
func (fs *FS) decryptSymlinkTarget(cData64 string) (string, error) {
if cData64 == "" {
return "", nil
@@ -392,14 +394,16 @@ func (fs *FS) decryptSymlinkTarget(cData64 string) (string, error) {
return string(data), nil
}
-// Readlink implements pathfs.Filesystem.
+// Readlink - FUSE call.
+//
+// Symlink-safe through openBackingDir() + Readlinkat().
func (fs *FS) Readlink(relPath string, context *fuse.Context) (out string, status fuse.Status) {
- cPath, err := fs.encryptPath(relPath)
+ dirfd, cName, err := fs.openBackingDir(relPath)
if err != nil {
return "", fuse.ToStatus(err)
}
- cAbsPath := filepath.Join(fs.args.Cipherdir, cPath)
- cTarget, err := os.Readlink(cAbsPath)
+ defer syscall.Close(dirfd)
+ cTarget, err := syscallcompat.Readlinkat(dirfd, cName)
if err != nil {
return "", fuse.ToStatus(err)
}
@@ -409,7 +413,7 @@ func (fs *FS) Readlink(relPath string, context *fuse.Context) (out string, statu
// Symlinks are encrypted like file contents (GCM) and base64-encoded
target, err := fs.decryptSymlinkTarget(cTarget)
if err != nil {
- tlog.Warn.Printf("Readlink %q: decrypting target failed: %v", cPath, err)
+ tlog.Warn.Printf("Readlink %q: decrypting target failed: %v", cName, err)
return "", fuse.EIO
}
return string(target), fuse.OK
diff --git a/internal/syscallcompat/sys_common.go b/internal/syscallcompat/sys_common.go
index c1fd00a..33ed807 100644
--- a/internal/syscallcompat/sys_common.go
+++ b/internal/syscallcompat/sys_common.go
@@ -10,10 +10,8 @@ import (
// It is not defined on Darwin, so we use the Linux value.
const PATH_MAX = 4096
-// Readlinkat exists both in Linux and in MacOS 10.10+. We may add an
-// emulated version for users on older MacOS versions if there is
-// demand.
-// Buffer allocation is handled internally, unlike the bare unix.Readlinkat.
+// Readlinkat is a convenience wrapper around unix.Readlinkat() that takes
+// care of buffer sizing. Implemented like os.Readlink().
func Readlinkat(dirfd int, path string) (string, error) {
// Allocate the buffer exponentially like os.Readlink does.
for bufsz := 128; ; bufsz *= 2 {