fusefrontend_reverse: use OpenNofollow in findLongnameParent
Protects findLongnameParent against symlink races. Also add comments to several functions along the way. Reported at https://github.com/rfjakob/gocryptfs/issues/165
This commit is contained in:
parent
8951eb2472
commit
959e1fc1e2
@ -2,7 +2,6 @@ package fusefrontend_reverse
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
"os"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -13,6 +12,7 @@ import (
|
|||||||
|
|
||||||
"github.com/rfjakob/gocryptfs/internal/nametransform"
|
"github.com/rfjakob/gocryptfs/internal/nametransform"
|
||||||
"github.com/rfjakob/gocryptfs/internal/pathiv"
|
"github.com/rfjakob/gocryptfs/internal/pathiv"
|
||||||
|
"github.com/rfjakob/gocryptfs/internal/syscallcompat"
|
||||||
"github.com/rfjakob/gocryptfs/internal/tlog"
|
"github.com/rfjakob/gocryptfs/internal/tlog"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -27,6 +27,9 @@ const (
|
|||||||
shortNameMax = 175
|
shortNameMax = 175
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// longnameParentCache maps dir+"/"+longname to plaintextname.
|
||||||
|
// Yes, the combination of relative plaintext dir path and encrypted
|
||||||
|
// longname is strange, but works fine as a map index.
|
||||||
var longnameParentCache map[string]string
|
var longnameParentCache map[string]string
|
||||||
var longnameCacheLock sync.Mutex
|
var longnameCacheLock sync.Mutex
|
||||||
|
|
||||||
@ -48,7 +51,9 @@ func initLongnameCache() {
|
|||||||
go longnameCacheCleaner()
|
go longnameCacheCleaner()
|
||||||
}
|
}
|
||||||
|
|
||||||
// findLongnameParent converts "gocryptfs.longname.XYZ" to the plaintext name
|
// findLongnameParent converts "longname" = "gocryptfs.longname.XYZ" to the
|
||||||
|
// plaintext name. "dir" = relative plaintext path to the directory the
|
||||||
|
// longname file is in, "dirIV" = directory IV of the directory.
|
||||||
func (rfs *ReverseFS) findLongnameParent(dir string, dirIV []byte, longname string) (plaintextName string, err error) {
|
func (rfs *ReverseFS) findLongnameParent(dir string, dirIV []byte, longname string) (plaintextName string, err error) {
|
||||||
longnameCacheLock.Lock()
|
longnameCacheLock.Lock()
|
||||||
hit := longnameParentCache[dir+"/"+longname]
|
hit := longnameParentCache[dir+"/"+longname]
|
||||||
@ -56,26 +61,27 @@ func (rfs *ReverseFS) findLongnameParent(dir string, dirIV []byte, longname stri
|
|||||||
if hit != "" {
|
if hit != "" {
|
||||||
return hit, nil
|
return hit, nil
|
||||||
}
|
}
|
||||||
absDir := filepath.Join(rfs.args.Cipherdir, dir)
|
fd, err := syscallcompat.OpenNofollow(rfs.args.Cipherdir, dir, syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
|
||||||
dirfd, err := os.Open(absDir)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("findLongnameParent: opendir failed: %v\n", err)
|
tlog.Warn.Printf("findLongnameParent: opendir failed: %v\n", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
dirEntries, err := dirfd.Readdirnames(-1)
|
dirEntries, err := syscallcompat.Getdents(fd)
|
||||||
dirfd.Close()
|
syscall.Close(fd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tlog.Warn.Printf("findLongnameParent: Readdirnames failed: %v\n", err)
|
tlog.Warn.Printf("findLongnameParent: Getdents failed: %v\n", err)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
longnameCacheLock.Lock()
|
longnameCacheLock.Lock()
|
||||||
defer longnameCacheLock.Unlock()
|
defer longnameCacheLock.Unlock()
|
||||||
for _, plaintextName = range dirEntries {
|
for _, entry := range dirEntries {
|
||||||
|
plaintextName := entry.Name
|
||||||
if len(plaintextName) <= shortNameMax {
|
if len(plaintextName) <= shortNameMax {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
cName := rfs.nameTransform.EncryptName(plaintextName, dirIV)
|
cName := rfs.nameTransform.EncryptName(plaintextName, dirIV)
|
||||||
if len(cName) <= syscall.NAME_MAX {
|
if len(cName) <= syscall.NAME_MAX {
|
||||||
|
// Entry should have been skipped by the "continue" above
|
||||||
log.Panic("logic error or wrong shortNameMax constant?")
|
log.Panic("logic error or wrong shortNameMax constant?")
|
||||||
}
|
}
|
||||||
hName := rfs.nameTransform.HashLongName(cName)
|
hName := rfs.nameTransform.HashLongName(cName)
|
||||||
|
@ -24,6 +24,9 @@ func (rfs *ReverseFS) abs(relPath string, err error) (string, error) {
|
|||||||
return filepath.Join(rfs.args.Cipherdir, relPath), nil
|
return filepath.Join(rfs.args.Cipherdir, relPath), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rDecryptName decrypts the ciphertext name "cName", given the dirIV of the
|
||||||
|
// directory "cName" lies in. The relative plaintext path to the directory
|
||||||
|
// "pDir" is used if a "gocryptfs.longname.XYZ.name" must be resolved.
|
||||||
func (rfs *ReverseFS) rDecryptName(cName string, dirIV []byte, pDir string) (pName string, err error) {
|
func (rfs *ReverseFS) rDecryptName(cName string, dirIV []byte, pDir string) (pName string, err error) {
|
||||||
nameType := nametransform.NameType(cName)
|
nameType := nametransform.NameType(cName)
|
||||||
if nameType == nametransform.LongNameNone {
|
if nameType == nametransform.LongNameNone {
|
||||||
@ -58,6 +61,8 @@ func (rfs *ReverseFS) rDecryptName(cName string, dirIV []byte, pDir string) (pNa
|
|||||||
return pName, nil
|
return pName, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decryptPath decrypts a relative ciphertext path to a relative plaintext
|
||||||
|
// path.
|
||||||
func (rfs *ReverseFS) decryptPath(relPath string) (string, error) {
|
func (rfs *ReverseFS) decryptPath(relPath string) (string, error) {
|
||||||
if rfs.args.PlaintextNames || relPath == "" {
|
if rfs.args.PlaintextNames || relPath == "" {
|
||||||
return relPath, nil
|
return relPath, nil
|
||||||
|
@ -17,6 +17,8 @@ type rPathCacheContainer struct {
|
|||||||
dirIV []byte
|
dirIV []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// lookup relative ciphertext path "cPath". Returns dirIV, relative
|
||||||
|
// plaintext path.
|
||||||
func (c *rPathCacheContainer) lookup(cPath string) ([]byte, string) {
|
func (c *rPathCacheContainer) lookup(cPath string) ([]byte, string) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
@ -28,7 +30,9 @@ func (c *rPathCacheContainer) lookup(cPath string) ([]byte, string) {
|
|||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// store - write entry for "cPath" into the cache
|
// store - write entry for the directory at relative ciphertext path "cPath"
|
||||||
|
// into the cache.
|
||||||
|
// "dirIV" = directory IV of the directory, "pPath" = relative plaintext path
|
||||||
func (c *rPathCacheContainer) store(cPath string, dirIV []byte, pPath string) {
|
func (c *rPathCacheContainer) store(cPath string, dirIV []byte, pPath string) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
defer c.Unlock()
|
defer c.Unlock()
|
||||||
@ -37,4 +41,5 @@ func (c *rPathCacheContainer) store(cPath string, dirIV []byte, pPath string) {
|
|||||||
c.pPath = pPath
|
c.pPath = pPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// rPathCache: see rPathCacheContainer above for a detailed description
|
||||||
var rPathCache rPathCacheContainer
|
var rPathCache rPathCacheContainer
|
||||||
|
Loading…
x
Reference in New Issue
Block a user