diff options
| author | Jakob Unterwurzacher | 2021-08-20 17:06:18 +0200 | 
|---|---|---|
| committer | Jakob Unterwurzacher | 2021-08-20 17:06:18 +0200 | 
| commit | fbccb160438aba6f1e16b26a982122c726afee1a (patch) | |
| tree | 1faac5ad3587a302fff40a8354382cda21823f3a | |
| parent | 14bf80301b4f3f1fb56f2f0b73de0dcc4aab5216 (diff) | |
-deterministic-names: implement for reverse mode, too
| -rw-r--r-- | internal/fusefrontend_reverse/ctlsock_interface.go | 3 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/node_dir_ops.go | 19 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/node_helpers.go | 7 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/rpath.go | 14 | ||||
| -rw-r--r-- | internal/fusefrontend_reverse/virtualnode.go | 8 | ||||
| -rw-r--r-- | tests/cli/cli_test.go | 6 | ||||
| -rw-r--r-- | tests/reverse/correctness_test.go | 8 | ||||
| -rw-r--r-- | tests/reverse/inomap_test.go | 6 | ||||
| -rw-r--r-- | tests/reverse/main_test.go | 23 | ||||
| -rw-r--r-- | tests/reverse/one_file_system_test.go | 29 | 
10 files changed, 77 insertions, 46 deletions
| diff --git a/internal/fusefrontend_reverse/ctlsock_interface.go b/internal/fusefrontend_reverse/ctlsock_interface.go index 2157044..1cfdf3e 100644 --- a/internal/fusefrontend_reverse/ctlsock_interface.go +++ b/internal/fusefrontend_reverse/ctlsock_interface.go @@ -7,7 +7,6 @@ import (  	"golang.org/x/sys/unix"  	"github.com/rfjakob/gocryptfs/internal/ctlsocksrv" -	"github.com/rfjakob/gocryptfs/internal/pathiv"  )  // Verify that the interface is implemented. @@ -22,7 +21,7 @@ func (rn *RootNode) EncryptPath(plainPath string) (string, error) {  	cipherPath := ""  	parts := strings.Split(plainPath, "/")  	for _, part := range parts { -		dirIV := pathiv.Derive(cipherPath, pathiv.PurposeDirIV) +		dirIV := rn.deriveDirIV(cipherPath)  		encryptedPart, err := rn.nameTransform.EncryptName(part, dirIV)  		if err != nil {  			return "", err diff --git a/internal/fusefrontend_reverse/node_dir_ops.go b/internal/fusefrontend_reverse/node_dir_ops.go index 21b9775..2592ebc 100644 --- a/internal/fusefrontend_reverse/node_dir_ops.go +++ b/internal/fusefrontend_reverse/node_dir_ops.go @@ -13,7 +13,6 @@ import (  	"github.com/rfjakob/gocryptfs/internal/configfile"  	"github.com/rfjakob/gocryptfs/internal/cryptocore"  	"github.com/rfjakob/gocryptfs/internal/nametransform" -	"github.com/rfjakob/gocryptfs/internal/pathiv"  	"github.com/rfjakob/gocryptfs/internal/syscallcompat"  	"github.com/rfjakob/gocryptfs/internal/tlog"  ) @@ -23,20 +22,16 @@ import (  // This function is symlink-safe through use of openBackingDir() and  // ReadDirIVAt().  func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.Errno) { -	// Virtual files: at least one gocryptfs.diriv file -	virtualFiles := []fuse.DirEntry{ -		{Mode: virtualFileMode, Name: nametransform.DirIVFilename}, -	}  	rn := n.rootNode() +	// Should we present a virtual gocryptfs.diriv? +	var virtualFiles []fuse.DirEntry +	if !rn.args.PlaintextNames && !rn.args.DeterministicNames { +		virtualFiles = append(virtualFiles, fuse.DirEntry{Mode: virtualFileMode, Name: nametransform.DirIVFilename}) +	}  	// This directory is a mountpoint. Present it as empty.  	if rn.args.OneFileSystem && n.isOtherFilesystem { -		if rn.args.PlaintextNames { -			return fs.NewListDirStream(nil), 0 -		} else { -			// An "empty" directory still has a gocryptfs.diriv file! -			return fs.NewListDirStream(virtualFiles), 0 -		} +		return fs.NewListDirStream(virtualFiles), 0  	}  	d, errno := n.prepareAtSyscall("") @@ -64,7 +59,7 @@ func (n *Node) Readdir(ctx context.Context) (stream fs.DirStream, errno syscall.  		return n.readdirPlaintextnames(entries)  	} -	dirIV := pathiv.Derive(d.cPath, pathiv.PurposeDirIV) +	dirIV := rn.deriveDirIV(d.cPath)  	// Encrypt names  	for i := range entries {  		var cName string diff --git a/internal/fusefrontend_reverse/node_helpers.go b/internal/fusefrontend_reverse/node_helpers.go index 7b286a0..b7dc086 100644 --- a/internal/fusefrontend_reverse/node_helpers.go +++ b/internal/fusefrontend_reverse/node_helpers.go @@ -2,6 +2,7 @@ package fusefrontend_reverse  import (  	"context" +	"log"  	"path/filepath"  	"syscall" @@ -129,8 +130,8 @@ func (n *Node) lookupLongnameName(ctx context.Context, nameFile string, out *fus  		return  	}  	defer syscall.Close(fd) -	diriv := pathiv.Derive(d.cPath, pathiv.PurposeDirIV)  	rn := n.rootNode() +	diriv := rn.deriveDirIV(d.cPath)  	pName, cFullname, errno := rn.findLongnameParent(fd, diriv, nameFile)  	if errno != 0 {  		return @@ -160,6 +161,10 @@ func (n *Node) lookupLongnameName(ctx context.Context, nameFile string, out *fus  // lookupDiriv returns a new Inode for a gocryptfs.diriv file inside `n`.  func (n *Node) lookupDiriv(ctx context.Context, out *fuse.EntryOut) (ch *fs.Inode, errno syscall.Errno) { +	if rn := n.rootNode(); rn.args.DeterministicNames { +		log.Panic("BUG: lookupDiriv called but DeterministicNames is set") +	} +  	d, errno := n.prepareAtSyscall("")  	if errno != 0 {  		return diff --git a/internal/fusefrontend_reverse/rpath.go b/internal/fusefrontend_reverse/rpath.go index 199473b..7ebedd7 100644 --- a/internal/fusefrontend_reverse/rpath.go +++ b/internal/fusefrontend_reverse/rpath.go @@ -2,6 +2,7 @@ package fusefrontend_reverse  import (  	"encoding/base64" +	"log"  	"path/filepath"  	"strings"  	"syscall" @@ -72,7 +73,7 @@ func (rn *RootNode) decryptPath(cPath string) (string, error) {  		// Start at the top and recurse  		currentCipherDir := filepath.Join(parts[:i]...)  		currentPlainDir := filepath.Join(transformedParts[:i]...) -		dirIV := pathiv.Derive(currentCipherDir, pathiv.PurposeDirIV) +		dirIV := rn.deriveDirIV(currentCipherDir)  		transformedPart, err := rn.rDecryptName(parts[i], dirIV, currentPlainDir)  		if err != nil {  			return "", err @@ -83,6 +84,17 @@ func (rn *RootNode) decryptPath(cPath string) (string, error) {  	return pRelPath, nil  } +// deriveDirIV wraps pathiv.Derive but takes DeterministicNames into account. +func (rn *RootNode) deriveDirIV(cPath string) []byte { +	if rn.args.PlaintextNames { +		log.Panic("BUG: deriveDirIV called but PlaintextNames is set") +	} +	if rn.args.DeterministicNames { +		return make([]byte, nametransform.DirIVLen) +	} +	return pathiv.Derive(cPath, pathiv.PurposeDirIV) +} +  // openBackingDir receives an already decrypted relative path  // "pRelPath", opens the directory that contains the target file/dir  // and returns the fd to the directory and the decrypted name of the diff --git a/internal/fusefrontend_reverse/virtualnode.go b/internal/fusefrontend_reverse/virtualnode.go index 2ee9548..328f021 100644 --- a/internal/fusefrontend_reverse/virtualnode.go +++ b/internal/fusefrontend_reverse/virtualnode.go @@ -43,9 +43,11 @@ func (n *Node) lookupFileType(cName string) fileType {  	rn := n.rootNode()  	// In -plaintextname mode, neither diriv nor longname files exist.  	if !rn.args.PlaintextNames { -		// Is it a gocryptfs.diriv file? -		if cName == nametransform.DirIVFilename { -			return typeDiriv +		if !rn.args.DeterministicNames { +			// Is it a gocryptfs.diriv file? +			if cName == nametransform.DirIVFilename { +				return typeDiriv +			}  		}  		// Is it a gocryptfs.longname.*.name file?  		if t := nametransform.NameType(cName); t == nametransform.LongNameFilename { diff --git a/tests/cli/cli_test.go b/tests/cli/cli_test.go index f4162f8..85a8006 100644 --- a/tests/cli/cli_test.go +++ b/tests/cli/cli_test.go @@ -995,9 +995,3 @@ func TestMountCreat(t *testing.T) {  		test_helpers.UnmountPanic(mnt)  	}  } - -// Test -init -deterministic-names -func TestInitDeterministicNames(t *testing.T) { -	dir := test_helpers.InitFS(t, "-deterministic-names") - -} diff --git a/tests/reverse/correctness_test.go b/tests/reverse/correctness_test.go index 9d7a1c8..87d2f12 100644 --- a/tests/reverse/correctness_test.go +++ b/tests/reverse/correctness_test.go @@ -119,10 +119,10 @@ func TestConfigMapping(t *testing.T) {  	}  } -// Check that the access() syscall works on virtual files -func TestAccessVirtual(t *testing.T) { -	if plaintextnames { -		t.Skip("test makes no sense for plaintextnames") +// Check that the access() syscall works on virtual gocryptfs.diriv files +func TestAccessVirtualDirIV(t *testing.T) { +	if plaintextnames || deterministic_names { +		t.Skip("test makes no sense for plaintextnames or deterministic_names")  	}  	var R_OK uint32 = 4  	var W_OK uint32 = 2 diff --git a/tests/reverse/inomap_test.go b/tests/reverse/inomap_test.go index e6fc525..d5544c8 100644 --- a/tests/reverse/inomap_test.go +++ b/tests/reverse/inomap_test.go @@ -130,8 +130,10 @@ func TestVirtualFileIno(t *testing.T) {  	}  	// Lower 48 bits should come from the backing file  	const mask = 0xffffffffffff -	if origInos.parent&mask != cipherInos.diriv&mask { -		t.Errorf("diriv ino mismatch: %#x vs %#x", origInos.parent, cipherInos.diriv) +	if !deterministic_names { // no diriv files with -deterministic-names +		if origInos.parent&mask != cipherInos.diriv&mask { +			t.Errorf("diriv ino mismatch: %#x vs %#x", origInos.parent, cipherInos.diriv) +		}  	}  	if origInos.child != cipherInos.child {  		t.Errorf("child ino mismatch: %d vs %d", origInos.child, cipherInos.child) diff --git a/tests/reverse/main_test.go b/tests/reverse/main_test.go index 3425289..3b9e7d0 100644 --- a/tests/reverse/main_test.go +++ b/tests/reverse/main_test.go @@ -2,6 +2,7 @@ package reverse_test  import (  	"bytes" +	"fmt"  	"os"  	"testing" @@ -9,8 +10,13 @@ import (  )  var x240 = string(bytes.Repeat([]byte("x"), 240)) + +// plaintextnames is true when the currently running test has -plaintextnames active  var plaintextnames bool +// deterministic_names is true when the currently running test has -deterministic-names active +var deterministic_names bool +  // dirA is a normal directory  var dirA string @@ -24,10 +30,22 @@ var dirC string  // to "dirC".  func TestMain(m *testing.M) {  	var r int -	for _, plaintextnames = range []bool{false, true} { + +	testcases := []struct { +		plaintextnames      bool +		deterministic_names bool +	}{ +		{false, false}, +		{true, false}, +		{false, true}, +	} +	for i, tc := range testcases {  		argsA := []string{"-reverse"} -		if plaintextnames { +		plaintextnames, deterministic_names = tc.plaintextnames, tc.deterministic_names +		if tc.plaintextnames {  			argsA = append(argsA, "-plaintextnames") +		} else if tc.deterministic_names { +			argsA = append(argsA, "-deterministic-names")  		}  		dirA = test_helpers.InitFS(nil, argsA...)  		dirB = test_helpers.TmpDir + "/b" @@ -49,6 +67,7 @@ func TestMain(m *testing.M) {  		os.RemoveAll(dirC)  		if r != 0 { +			fmt.Printf("testcases[%d] = %#v failed\n", i, tc)  			os.Exit(r)  		}  	} diff --git a/tests/reverse/one_file_system_test.go b/tests/reverse/one_file_system_test.go index 61fdb61..a3e441f 100644 --- a/tests/reverse/one_file_system_test.go +++ b/tests/reverse/one_file_system_test.go @@ -1,8 +1,9 @@ -package reverse +package reverse_test  import (  	"io/ioutil"  	"net/url" +	"os"  	"runtime"  	"syscall"  	"testing" @@ -10,7 +11,10 @@ import (  	"github.com/rfjakob/gocryptfs/tests/test_helpers"  ) -func doTestOneFileSystem(t *testing.T, plaintextnames bool) { +func TestOneFileSystem(t *testing.T) { +	if runtime.GOOS != "linux" { +		t.Skip("only works on linux") +	}  	// Let's not explode with "TempDir: pattern contains path separator"  	myEscapedName := url.PathEscape(t.Name())  	mnt, err := ioutil.TempDir(test_helpers.TmpDir, myEscapedName) @@ -20,6 +24,8 @@ func doTestOneFileSystem(t *testing.T, plaintextnames bool) {  	cliArgs := []string{"-reverse", "-zerokey", "-one-file-system"}  	if plaintextnames {  		cliArgs = append(cliArgs, "-plaintextnames") +	} else if deterministic_names { +		cliArgs = append(cliArgs, "-deterministic-names")  	}  	test_helpers.MountOrFatal(t, "/", mnt, cliArgs...)  	defer test_helpers.UnmountErr(mnt) @@ -48,25 +54,22 @@ func doTestOneFileSystem(t *testing.T, plaintextnames bool) {  		t.Skip("no mountpoints found, nothing to test")  	}  	for _, m := range mountpoints { -		e, err := ioutil.ReadDir(mnt + "/" + m) +		dir, err := os.Open(mnt + "/" + m) +		if err != nil { +			t.Error(err) +		} +		defer dir.Close() +		e, err := dir.Readdirnames(-1)  		if err != nil {  			t.Error(err)  		}  		expected := 1 -		if plaintextnames { +		if plaintextnames || deterministic_names {  			expected = 0  		}  		if len(e) != expected { -			t.Errorf("mountpoint %q does not look empty: %v", m, e) +			t.Errorf("mountpoint %q should have %d entries, actually has: %v", m, expected, e)  		}  	}  	t.Logf("tested %d mountpoints: %v", len(mountpoints), mountpoints)  } - -func TestOneFileSystem(t *testing.T) { -	if runtime.GOOS != "linux" { -		t.Skip("only works on linux") -	} -	t.Run("normal", func(t *testing.T) { doTestOneFileSystem(t, false) }) -	t.Run("plaintextnames", func(t *testing.T) { doTestOneFileSystem(t, true) }) -} | 
