fusefrontend_reverse: secure Readlink against symlink races

...by using Readlinkat.

Tracking ticket: https://github.com/rfjakob/gocryptfs/issues/165
This commit is contained in:
Jakob Unterwurzacher 2017-12-06 21:10:49 +01:00
parent f97494e89b
commit e042eb38fa

View File

@ -3,7 +3,6 @@ package fusefrontend_reverse
import ( import (
"fmt" "fmt"
"log" "log"
"os"
"path/filepath" "path/filepath"
"syscall" "syscall"
@ -321,19 +320,26 @@ func (rfs *ReverseFS) StatFs(path string) *fuse.StatfsOut {
} }
// Readlink - FUSE call // Readlink - FUSE call
func (rfs *ReverseFS) Readlink(cipherPath string, context *fuse.Context) (string, fuse.Status) { func (rfs *ReverseFS) Readlink(relPath string, context *fuse.Context) (string, fuse.Status) {
absPath, err := rfs.abs(rfs.decryptPath(cipherPath)) // Decrypt path to "plaintext relative path"
pRelPath, err := rfs.decryptPath(relPath)
if err != nil { if err != nil {
return "", fuse.ToStatus(err) return "", fuse.ToStatus(err)
} }
plainTarget, err := os.Readlink(absPath) // 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 := syscallcompat.Readlinkat(dirFd, filepath.Base(pRelPath))
syscall.Close(dirFd)
if err != nil { if err != nil {
return "", fuse.ToStatus(err) return "", fuse.ToStatus(err)
} }
if rfs.args.PlaintextNames { if rfs.args.PlaintextNames {
return plainTarget, fuse.OK 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 // Symlinks are encrypted like file contents and base64-encoded
cBinTarget := rfs.contentEnc.EncryptBlockNonce([]byte(plainTarget), 0, nil, nonce) cBinTarget := rfs.contentEnc.EncryptBlockNonce([]byte(plainTarget), 0, nil, nonce)
cTarget := rfs.nameTransform.B64.EncodeToString(cBinTarget) cTarget := rfs.nameTransform.B64.EncodeToString(cBinTarget)