summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Unterwurzacher2019-01-02 21:45:40 +0100
committerJakob Unterwurzacher2019-01-02 21:45:40 +0100
commit2b12bba274ba75f76ac8c2af3790e4190b32396f (patch)
treeba8a637f0677cbe387220de9f4742dd0e33c639c
parent59f1300591d44b1e5d8187b54951c03d6120289f (diff)
fusefronted: make EncryptPath symlink-safe
Finally allows us to delete EncryptPathDirIV.
-rw-r--r--internal/fusefrontend/ctlsock_interface.go28
-rw-r--r--internal/fusefrontend/names.go21
-rw-r--r--internal/nametransform/diriv.go67
-rw-r--r--internal/nametransform/names.go5
4 files changed, 28 insertions, 93 deletions
diff --git a/internal/fusefrontend/ctlsock_interface.go b/internal/fusefrontend/ctlsock_interface.go
index b29d150..15345f3 100644
--- a/internal/fusefrontend/ctlsock_interface.go
+++ b/internal/fusefrontend/ctlsock_interface.go
@@ -3,21 +3,45 @@ package fusefrontend
import (
"fmt"
"path"
+ "path/filepath"
"strings"
"syscall"
"github.com/rfjakob/gocryptfs/internal/ctlsock"
"github.com/rfjakob/gocryptfs/internal/nametransform"
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
+ "github.com/rfjakob/gocryptfs/internal/tlog"
)
var _ ctlsock.Interface = &FS{} // Verify that interface is implemented.
// EncryptPath implements ctlsock.Backend
//
-// TODO: this function is NOT symlink-safe.
+// Symlink-safe through openBackingDir().
func (fs *FS) EncryptPath(plainPath string) (string, error) {
- return fs.encryptPath(plainPath)
+ if plainPath == "" {
+ // Empty string gets encrypted as empty string
+ return plainPath, nil
+ }
+ if fs.args.PlaintextNames {
+ return plainPath, nil
+ }
+ // Encrypt path level by level using openBackingDir. Pretty inefficient,
+ // but does not matter here.
+ parts := strings.Split(plainPath, "/")
+ wd := ""
+ cPath := ""
+ for _, part := range parts {
+ wd = filepath.Join(wd, part)
+ dirfd, cName, err := fs.openBackingDir(wd)
+ if err != nil {
+ return "", err
+ }
+ syscall.Close(dirfd)
+ cPath = filepath.Join(cPath, cName)
+ }
+ tlog.Debug.Printf("encryptPath '%s' -> '%s'", plainPath, cPath)
+ return cPath, nil
}
// DecryptPath implements ctlsock.Backend
diff --git a/internal/fusefrontend/names.go b/internal/fusefrontend/names.go
index 36185e2..63f2e84 100644
--- a/internal/fusefrontend/names.go
+++ b/internal/fusefrontend/names.go
@@ -83,24 +83,3 @@ func (fs *FS) openBackingDir(relPath string) (dirfd int, cName string, err error
}
return dirfd, cName, nil
}
-
-// encryptPath - encrypt relative plaintext path
-//
-// TODO: this function is NOT symlink-safe because EncryptPathDirIV is not
-// symlink-safe.
-func (fs *FS) encryptPath(plainPath string) (string, error) {
- if plainPath != "" { // Empty path gets encrypted all the time without actual file accesses.
- fs.AccessedSinceLastCheck = 1
- } else { // Empty string gets encrypted as empty string
- return plainPath, nil
- }
- if fs.args.PlaintextNames {
- return plainPath, nil
- }
-
- fs.dirIVLock.RLock()
- cPath, err := fs.nameTransform.EncryptPathDirIV(plainPath, fs.args.Cipherdir)
- tlog.Debug.Printf("encryptPath '%s' -> '%s' (err: %v)", plainPath, cPath, err)
- fs.dirIVLock.RUnlock()
- return cPath, err
-}
diff --git a/internal/nametransform/diriv.go b/internal/nametransform/diriv.go
index b98de0c..93c4c68 100644
--- a/internal/nametransform/diriv.go
+++ b/internal/nametransform/diriv.go
@@ -25,26 +25,6 @@ const (
DirIVFilename = "gocryptfs.diriv"
)
-// ReadDirIV - read the "gocryptfs.diriv" file from "dir" (absolute ciphertext path)
-// This function is exported because it allows for an efficient readdir implementation.
-// If the directory itself cannot be opened, a syscall error will be returned.
-// Otherwise, a fmt.Errorf() error value is returned with the details.
-//
-// TODO: this function is not symlink-safe and should be deleted once the only
-// remaining user, EncryptPathDirIV(), is gone.
-func ReadDirIV(dir string) (iv []byte, err error) {
- fd, err := os.Open(filepath.Join(dir, DirIVFilename))
- if err != nil {
- // Note: getting errors here is normal because of concurrent deletes.
- // Strip the useless annotation that os.Open has added and return
- // the plain syscall error. The caller will log a nice message.
- err2 := err.(*os.PathError)
- return nil, err2.Err
- }
- defer fd.Close()
- return fdReadDirIV(fd)
-}
-
// ReadDirIVAt reads "gocryptfs.diriv" from the directory that is opened as "dirfd".
// Using the dirfd makes it immune to concurrent renames of the directory.
func ReadDirIVAt(dirfd int) (iv []byte, err error) {
@@ -132,53 +112,6 @@ func (be *NameTransform) EncryptAndHashName(name string, iv []byte) string {
return cName
}
-// EncryptPathDirIV - encrypt relative plaintext path "plainPath" using EME with
-// DirIV. "rootDir" is the backing storage root directory.
-// Components that are longer than 255 bytes are hashed if be.longnames == true.
-//
-// TODO: EncryptPathDirIV is NOT SAFE against symlink races. This function
-// should eventually be deleted.
-func (be *NameTransform) EncryptPathDirIV(plainPath string, rootDir string) (string, error) {
- var err error
- // Empty string means root directory
- if plainPath == "" {
- return plainPath, nil
- }
- // Reject names longer than 255 bytes.
- baseName := filepath.Base(plainPath)
- if len(baseName) > unix.NAME_MAX {
- return "", syscall.ENAMETOOLONG
- }
- // If we have the iv and the encrypted directory name in the cache, we
- // can skip the directory walk. This optimization yields a 10% improvement
- // in the tar extract benchmark.
- parentDir := Dir(plainPath)
- if iv, cParentDir := be.DirIVCache.Lookup(parentDir); iv != nil {
- cBaseName := be.EncryptAndHashName(baseName, iv)
- return filepath.Join(cParentDir, cBaseName), nil
- }
- // We have to walk the directory tree, starting at the root directory.
- // ciphertext working directory (relative path)
- cipherWD := ""
- // plaintext working directory (relative path)
- plainWD := ""
- plainNames := strings.Split(plainPath, "/")
- for _, plainName := range plainNames {
- iv, _ := be.DirIVCache.Lookup(plainWD)
- if iv == nil {
- iv, err = ReadDirIV(filepath.Join(rootDir, cipherWD))
- if err != nil {
- return "", err
- }
- be.DirIVCache.Store(plainWD, iv, cipherWD)
- }
- cipherName := be.EncryptAndHashName(plainName, iv)
- cipherWD = filepath.Join(cipherWD, cipherName)
- plainWD = filepath.Join(plainWD, plainName)
- }
- return cipherWD, nil
-}
-
// Dir is like filepath.Dir but returns "" instead of ".".
func Dir(path string) string {
d := filepath.Dir(path)
diff --git a/internal/nametransform/names.go b/internal/nametransform/names.go
index 22e639a..33128b9 100644
--- a/internal/nametransform/names.go
+++ b/internal/nametransform/names.go
@@ -74,11 +74,10 @@ func (n *NameTransform) DecryptName(cipherName string, iv []byte) (string, error
}
// EncryptName encrypts "plainName", returns a base64-encoded "cipherName64".
-// Used internally by EncryptPathDirIV().
// The encryption is either CBC or EME, depending on "useEME".
//
-// This function is exported because fusefrontend needs access to the full (not hashed)
-// name if longname is used. Otherwise you should use EncryptPathDirIV()
+// This function is exported because in some cases, fusefrontend needs access
+// to the full (not hashed) name if longname is used.
func (n *NameTransform) EncryptName(plainName string, iv []byte) (cipherName64 string) {
bin := []byte(plainName)
bin = pad16(bin)