fusefrontend: make Readlink() symlink-safe

Now symlink-safe through Readlinkat().
This commit is contained in:
Jakob Unterwurzacher 2018-11-04 22:01:18 +01:00
parent 21f1f858b9
commit 4fae240153
2 changed files with 11 additions and 9 deletions

View File

@ -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

View File

@ -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 {