diff options
| -rw-r--r-- | Documentation/MANPAGE.md | 5 | ||||
| -rw-r--r-- | cli_args.go | 3 | ||||
| -rw-r--r-- | init_dir.go | 2 | ||||
| -rw-r--r-- | internal/fusefrontend/args.go | 2 | ||||
| -rw-r--r-- | internal/fusefrontend/node_dir_ops.go | 3 | ||||
| -rw-r--r-- | internal/nametransform/diriv.go | 16 | ||||
| -rw-r--r-- | mount.go | 1 | ||||
| -rw-r--r-- | tests/test_helpers/helpers.go | 2 | ||||
| -rw-r--r-- | tests/zerodiriv/zerodiriv_test.go | 85 | 
9 files changed, 106 insertions, 13 deletions
| diff --git a/Documentation/MANPAGE.md b/Documentation/MANPAGE.md index 1547591..07f063e 100644 --- a/Documentation/MANPAGE.md +++ b/Documentation/MANPAGE.md @@ -545,6 +545,11 @@ useful in regression testing.  Applies to: all actions. +#### -zerodiriv +Create diriv as all-zero files + +Applies to: all actions without `-plaintextnames`. +  #### \-\-  Stop option parsing. Helpful when CIPHERDIR may start with a  dash "-". diff --git a/cli_args.go b/cli_args.go index 058f932..76e8d30 100644 --- a/cli_args.go +++ b/cli_args.go @@ -30,7 +30,7 @@ type argContainer struct {  	plaintextnames, quiet, nosyslog, wpanic,  	longnames, allow_other, reverse, aessiv, nonempty, raw64,  	noprealloc, speed, hkdf, serialize_reads, forcedecode, hh, info, -	sharedstorage, devrandom, fsck, one_file_system bool +	sharedstorage, devrandom, fsck, one_file_system, zerodiriv bool  	// Mount options with opposites  	dev, nodev, suid, nosuid, exec, noexec, rw, ro, kernel_cache, acl bool  	masterkey, mountpoint, cipherdir, cpuprofile, @@ -179,6 +179,7 @@ func parseCliOpts(osArgs []string) (args argContainer) {  	flagSet.BoolVar(&args.devrandom, "devrandom", false, "Use /dev/random for generating master key")  	flagSet.BoolVar(&args.fsck, "fsck", false, "Run a filesystem check on CIPHERDIR")  	flagSet.BoolVar(&args.one_file_system, "one-file-system", false, "Don't cross filesystem boundaries") +	flagSet.BoolVar(&args.zerodiriv, "zerodiriv", false, "Create diriv as all-zero files")  	// Mount options with opposites  	flagSet.BoolVar(&args.dev, "dev", false, "Allow device files") diff --git a/init_dir.go b/init_dir.go index 54a44e4..ce5f98d 100644 --- a/init_dir.go +++ b/init_dir.go @@ -103,7 +103,7 @@ func initDir(args *argContainer) {  		// Open cipherdir (following symlinks)  		dirfd, err := syscall.Open(args.cipherdir, syscall.O_DIRECTORY|syscallcompat.O_PATH, 0)  		if err == nil { -			err = nametransform.WriteDirIVAt(dirfd) +			err = nametransform.WriteDirIVAt(dirfd, !args.zerodiriv)  			syscall.Close(dirfd)  		}  		if err != nil { diff --git a/internal/fusefrontend/args.go b/internal/fusefrontend/args.go index d92c3ff..02ffddb 100644 --- a/internal/fusefrontend/args.go +++ b/internal/fusefrontend/args.go @@ -53,4 +53,6 @@ type Args struct {  	// like rsync's `--one-file-system` does.  	// Only applicable to reverse mode.  	OneFileSystem bool +	// ZeroDirIV creates diriv files as all-zero files +	ZeroDirIV bool  } diff --git a/internal/fusefrontend/node_dir_ops.go b/internal/fusefrontend/node_dir_ops.go index 6d03544..b43a4e4 100644 --- a/internal/fusefrontend/node_dir_ops.go +++ b/internal/fusefrontend/node_dir_ops.go @@ -35,6 +35,7 @@ func haveDsstore(entries []fuse.DirEntry) bool {  // should be a handle to the parent directory, cName is the name of the new  // directory and mode specifies the access permissions to use.  func (n *Node) mkdirWithIv(dirfd int, cName string, mode uint32, context *fuse.Context) error { +  	rn := n.rootNode()  	// Between the creation of the directory and the creation of gocryptfs.diriv  	// the directory is inconsistent. Take the lock to prevent other readers @@ -48,7 +49,7 @@ func (n *Node) mkdirWithIv(dirfd int, cName string, mode uint32, context *fuse.C  	dirfd2, err := syscallcompat.Openat(dirfd, cName, syscall.O_DIRECTORY|syscall.O_NOFOLLOW|syscallcompat.O_PATH, 0)  	if err == nil {  		// Create gocryptfs.diriv -		err = nametransform.WriteDirIVAt(dirfd2) +		err = nametransform.WriteDirIVAt(dirfd2, !rn.args.ZeroDirIV)  		syscall.Close(dirfd2)  	}  	if err != nil { diff --git a/internal/nametransform/diriv.go b/internal/nametransform/diriv.go index b10c899..a288aa5 100644 --- a/internal/nametransform/diriv.go +++ b/internal/nametransform/diriv.go @@ -1,7 +1,6 @@  package nametransform  import ( -	"bytes"  	"fmt"  	"io"  	"os" @@ -34,9 +33,6 @@ func ReadDirIVAt(dirfd int) (iv []byte, err error) {  	return fdReadDirIV(fd)  } -// allZeroDirIV is preallocated to quickly check if the data read from disk is all zero -var allZeroDirIV = make([]byte, DirIVLen) -  // fdReadDirIV reads and verifies the DirIV from an opened gocryptfs.diriv file.  func fdReadDirIV(fd *os.File) (iv []byte, err error) {  	// We want to detect if the file is bigger than DirIVLen, so @@ -50,9 +46,6 @@ func fdReadDirIV(fd *os.File) (iv []byte, err error) {  	if len(iv) != DirIVLen {  		return nil, fmt.Errorf("wanted %d bytes, got %d", DirIVLen, len(iv))  	} -	if bytes.Equal(iv, allZeroDirIV) { -		return nil, fmt.Errorf("diriv is all-zero") -	}  	return iv, nil  } @@ -60,8 +53,13 @@ func fdReadDirIV(fd *os.File) (iv []byte, err error) {  // "dirfd". On error we try to delete the incomplete file.  // This function is exported because it is used from fusefrontend, main,  // and also the automated tests. -func WriteDirIVAt(dirfd int) error { -	iv := cryptocore.RandBytes(DirIVLen) +func WriteDirIVAt(dirfd int, randomInitialization bool) error { +	var iv []byte +	if randomInitialization { +		iv = cryptocore.RandBytes(DirIVLen) +	} else { +		iv = make([]byte, DirIVLen) +	}  	// 0400 permissions: gocryptfs.diriv should never be modified after creation.  	// Don't use "ioutil.WriteFile", it causes trouble on NFS:  	// https://github.com/rfjakob/gocryptfs/commit/7d38f80a78644c8ec4900cc990bfb894387112ed @@ -276,6 +276,7 @@ func initFuseFrontend(args *argContainer) (rootNode fs.InodeEmbedder, wipeKeys f  		KernelCache:     args.kernel_cache,  		SharedStorage:   args.sharedstorage,  		OneFileSystem:   args.one_file_system, +		ZeroDirIV:       args.zerodiriv,  	}  	// confFile is nil when "-zerokey" or "-masterkey" was used  	if confFile != nil { diff --git a/tests/test_helpers/helpers.go b/tests/test_helpers/helpers.go index 87dba0a..f78c59c 100644 --- a/tests/test_helpers/helpers.go +++ b/tests/test_helpers/helpers.go @@ -110,7 +110,7 @@ func ResetTmpDir(createDirIV bool) {  		// Open cipherdir (following symlinks)  		dirfd, err := syscall.Open(DefaultCipherDir, syscall.O_DIRECTORY|syscallcompat.O_PATH, 0)  		if err == nil { -			err = nametransform.WriteDirIVAt(dirfd) +			err = nametransform.WriteDirIVAt(dirfd, true)  			syscall.Close(dirfd)  		}  		if err != nil { diff --git a/tests/zerodiriv/zerodiriv_test.go b/tests/zerodiriv/zerodiriv_test.go new file mode 100644 index 0000000..3fbbf47 --- /dev/null +++ b/tests/zerodiriv/zerodiriv_test.go @@ -0,0 +1,85 @@ +package zerodiriv + +// integration tests that target zerodiriv specifically + +import ( +	"bytes" +	"path/filepath" +	"io/ioutil" +	"os" +	"testing" + +	"github.com/rfjakob/gocryptfs/tests/test_helpers" +) + +var cDir string +var pDir string + +var testPw = []byte("test") + +// Create and mount "-zerodiriv" fs +func TestMain(m *testing.M) { +	cDir = test_helpers.InitFS(nil, "-zerodiriv") +	pDir = cDir + ".mnt" +	test_helpers.MountOrExit(cDir, pDir, "-zerodiriv", "-extpass", "echo test") +	r := m.Run() +	test_helpers.UnmountPanic(pDir) +	os.Exit(r) +} + +// diriv should be all-zero on newly created dirs +func TestZeroDirIV(t *testing.T) { +	// Create /dir1, move it and create it again +	var dirPath = pDir+"/dir1" +	var err = os.Mkdir(dirPath, 0777) +	if err != nil { +		t.Error(err) +	} +	err = os.Rename(dirPath, dirPath + ".bak") +	if err != nil { +		t.Error(err) +	} +	err = os.Mkdir(dirPath, 0777) +	if err != nil { +		t.Error(err) +	} + +	var matches []string +	matches, err = filepath.Glob(cDir+"/*/gocryptfs.diriv") +	if err != nil { +		t.Error(err) +	} + +	// The contents of the both diriv files must be the same +	var diriv0 []byte +	diriv0, err = ioutil.ReadFile(matches[0]) +	if err != nil { +		t.Error(err) +	} +	var diriv1 []byte +	diriv1, err = ioutil.ReadFile(matches[1]) +	if err != nil { +		t.Error(err) +	} +	if !bytes.Equal(diriv0, diriv1) { +		t.Errorf("both dirivs should have the same value") +	} +	// And equal to zero +	zerodiriv := make([]byte, len(diriv0)) +	if !bytes.Equal(diriv0, zerodiriv) { +		t.Errorf("both dirivs should be all-zero") +	} +} + +// root diriv should be all-zero +func TestZeroRootDirIV(t *testing.T) { +	// The contents of the diriv file must be zero +	diriv, err := ioutil.ReadFile(cDir+"/gocryptfs.diriv") +	if err != nil { +		t.Error(err) +	} +	zerodiriv := make([]byte, len(diriv)) +	if !bytes.Equal(diriv, zerodiriv) { +		t.Errorf("root diriv should be all-zero") +	} +} | 
