From 4fae240153a5300b7108bf5c2de2b6581c8ee7fd Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Sun, 4 Nov 2018 22:01:18 +0100 Subject: fusefrontend: make Readlink() symlink-safe Now symlink-safe through Readlinkat(). --- internal/fusefrontend/fs.go | 14 +++++++++----- internal/syscallcompat/sys_common.go | 6 ++---- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'internal') 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 { -- cgit v1.2.3