diff --git a/cryptfs/names_diriv.go b/cryptfs/names_diriv.go index c9debab..1415bcb 100644 --- a/cryptfs/names_diriv.go +++ b/cryptfs/names_diriv.go @@ -21,6 +21,15 @@ func (be *CryptFS) readDirIV(dir string) (iv []byte, err error) { return iv, nil } +// WriteDirIV - create diriv file inside "dir" (absolute path) +// This function is exported because it is used from pathfs_frontend +func (be *CryptFS) WriteDirIV(dir string) error { + iv := RandBytes(DIRIV_LEN) + file := filepath.Join(dir, DIRIV_FILENAME) + // 0444 permissions: the file is not secret but should not be written to + return ioutil.WriteFile(file, iv, 0444) +} + // EncryptPathDirIV - encrypt path using CBC with DirIV func (be *CryptFS) EncryptPathDirIV(plainPath string, rootDir string) (string, error) { if be.plaintextNames { diff --git a/pathfs_frontend/fs.go b/pathfs_frontend/fs.go index 48ea4a2..0e0d022 100644 --- a/pathfs_frontend/fs.go +++ b/pathfs_frontend/fs.go @@ -5,7 +5,6 @@ import ( "fmt" "sync" "syscall" - "io/ioutil" "os" "path/filepath" "time" @@ -20,7 +19,11 @@ type FS struct { *cryptfs.CryptFS pathfs.FileSystem // loopbackFileSystem, see go-fuse/fuse/pathfs/loopback.go backingDir string // Backing directory, cipherdir - dirivLock sync.RWMutex // Global lock that is taken if any "gocryptfs.diriv" file is modified + // dirIVLock: Lock()ed if any "gocryptfs.diriv" file is modified + // Readers must RLock() it to prevent them from seeing intermediate + // states + dirIVLock sync.RWMutex + } // Encrypted FUSE overlay filesystem @@ -217,16 +220,15 @@ func (fs *FS) Mkdir(relPath string, mode uint32, context *fuse.Context) (code fu if err != nil { return fuse.ToStatus(err) } - diriv := cryptfs.RandBytes(cryptfs.DIRIV_LEN) - dirivPath := filepath.Join(encPath, cryptfs.DIRIV_FILENAME) // Create directory + fs.dirIVLock.Lock() + defer fs.dirIVLock.Unlock() err = os.Mkdir(encPath, os.FileMode(mode)) if err != nil { return fuse.ToStatus(err) } // Create gocryptfs.diriv inside - // 0444 permissions: the file is not secret but should not be written to - err = ioutil.WriteFile(dirivPath, diriv, 0444) + err = fs.CryptFS.WriteDirIV(encPath) if err != nil { // This should not happen cryptfs.Warn.Printf("Creating %s in dir %s failed: %v\n", cryptfs.DIRIV_FILENAME, encPath, err) @@ -282,8 +284,8 @@ func (fs *FS) Rmdir(name string, context *fuse.Context) (code fuse.Status) { tmpName := fmt.Sprintf("gocryptfs.diriv.rmdir.%d", st.Ino) tmpDirivPath := filepath.Join(parentDir, tmpName) cryptfs.Debug.Printf("Rmdir: Renaming %s to %s\n", cryptfs.DIRIV_FILENAME, tmpDirivPath) - fs.dirivLock.Lock() // directory will be in an inconsistent state after the rename - defer fs.dirivLock.Unlock() + fs.dirIVLock.Lock() // directory will be in an inconsistent state after the rename + defer fs.dirIVLock.Unlock() err = os.Rename(dirivPath, tmpDirivPath) if err != nil { cryptfs.Warn.Printf("Rmdir: Renaming %s to %s failed: %v\n", cryptfs.DIRIV_FILENAME, tmpDirivPath, err) diff --git a/pathfs_frontend/names.go b/pathfs_frontend/names.go index 5842d83..9c6e010 100644 --- a/pathfs_frontend/names.go +++ b/pathfs_frontend/names.go @@ -3,9 +3,13 @@ package pathfs_frontend // This file handles filename encryption func (fs *FS) encryptPath(plainPath string) (string, error) { + fs.dirIVLock.RLock() + defer fs.dirIVLock.RUnlock() return fs.CryptFS.EncryptPathDirIV(plainPath, fs.backingDir) } func (fs *FS) decryptPath(cipherPath string) (string, error) { + fs.dirIVLock.RLock() + defer fs.dirIVLock.RUnlock() return fs.CryptFS.DecryptPathDirIV(cipherPath, fs.backingDir) }