aboutsummaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorJakob Unterwurzacher2017-12-06 21:10:49 +0100
committerJakob Unterwurzacher2017-12-06 21:13:08 +0100
commite042eb38fa1990b2539e6e690fd9713487337be1 (patch)
tree02f370efb12ac69e5d5433f18d94b8ef127a23f0 /internal
parentf97494e89bff7b15d1be5f4b2d047382a54e6094 (diff)
fusefrontend_reverse: secure Readlink against symlink races
...by using Readlinkat. Tracking ticket: https://github.com/rfjakob/gocryptfs/issues/165
Diffstat (limited to 'internal')
-rw-r--r--internal/fusefrontend_reverse/rfs.go16
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)