diff options
author | Jakob Unterwurzacher | 2017-12-06 21:10:49 +0100 |
---|---|---|
committer | Jakob Unterwurzacher | 2017-12-06 21:13:08 +0100 |
commit | e042eb38fa1990b2539e6e690fd9713487337be1 (patch) | |
tree | 02f370efb12ac69e5d5433f18d94b8ef127a23f0 | |
parent | f97494e89bff7b15d1be5f4b2d047382a54e6094 (diff) |
fusefrontend_reverse: secure Readlink against symlink races
...by using Readlinkat.
Tracking ticket: https://github.com/rfjakob/gocryptfs/issues/165
-rw-r--r-- | internal/fusefrontend_reverse/rfs.go | 16 |
1 files 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) |