From e042eb38fa1990b2539e6e690fd9713487337be1 Mon Sep 17 00:00:00 2001 From: Jakob Unterwurzacher Date: Wed, 6 Dec 2017 21:10:49 +0100 Subject: fusefrontend_reverse: secure Readlink against symlink races ...by using Readlinkat. Tracking ticket: https://github.com/rfjakob/gocryptfs/issues/165 --- internal/fusefrontend_reverse/rfs.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/internal/fusefrontend_reverse/rfs.go b/internal/fusefrontend_reverse/rfs.go index 0b9e34c..db10ce0 100644 --- a/internal/fusefrontend_reverse/rfs.go +++ b/internal/fusefrontend_reverse/rfs.go @@ -3,7 +3,6 @@ package fusefrontend_reverse import ( "fmt" "log" - "os" "path/filepath" "syscall" @@ -321,19 +320,26 @@ func (rfs *ReverseFS) StatFs(path string) *fuse.StatfsOut { } // Readlink - FUSE call -func (rfs *ReverseFS) Readlink(cipherPath string, context *fuse.Context) (string, fuse.Status) { - absPath, err := rfs.abs(rfs.decryptPath(cipherPath)) +func (rfs *ReverseFS) Readlink(relPath string, context *fuse.Context) (string, fuse.Status) { + // Decrypt path to "plaintext relative path" + pRelPath, err := rfs.decryptPath(relPath) + if err != nil { + return "", fuse.ToStatus(err) + } + // read the link target using Readlinkat + dirFd, err := syscallcompat.OpenNofollow(rfs.args.Cipherdir, filepath.Dir(pRelPath), syscall.O_RDONLY|syscall.O_DIRECTORY, 0) if err != nil { return "", fuse.ToStatus(err) } - plainTarget, err := os.Readlink(absPath) + plainTarget, err := syscallcompat.Readlinkat(dirFd, filepath.Base(pRelPath)) + syscall.Close(dirFd) if err != nil { return "", fuse.ToStatus(err) } if rfs.args.PlaintextNames { return plainTarget, fuse.OK } - nonce := pathiv.Derive(cipherPath, pathiv.PurposeSymlinkIV) + nonce := pathiv.Derive(relPath, pathiv.PurposeSymlinkIV) // Symlinks are encrypted like file contents and base64-encoded cBinTarget := rfs.contentEnc.EncryptBlockNonce([]byte(plainTarget), 0, nil, nonce) cTarget := rfs.nameTransform.B64.EncodeToString(cBinTarget) -- cgit v1.2.3