Skip to content

Commit

Permalink
-deterministic-names: implement for reverse mode, too
Browse files Browse the repository at this point in the history
  • Loading branch information
rfjakob committed Aug 20, 2021
1 parent 14bf803 commit fbccb16
Show file tree
Hide file tree
Showing 10 changed files with 77 additions and 46 deletions.
3 changes: 1 addition & 2 deletions internal/fusefrontend_reverse/ctlsock_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand Down
19 changes: 7 additions & 12 deletions internal/fusefrontend_reverse/node_dir_ops.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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("")
Expand Down Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion internal/fusefrontend_reverse/node_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fusefrontend_reverse

import (
"context"
"log"
"path/filepath"
"syscall"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
14 changes: 13 additions & 1 deletion internal/fusefrontend_reverse/rpath.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package fusefrontend_reverse

import (
"encoding/base64"
"log"
"path/filepath"
"strings"
"syscall"
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
8 changes: 5 additions & 3 deletions internal/fusefrontend_reverse/virtualnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
6 changes: 0 additions & 6 deletions tests/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")

}
8 changes: 4 additions & 4 deletions tests/reverse/correctness_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 4 additions & 2 deletions tests/reverse/inomap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
23 changes: 21 additions & 2 deletions tests/reverse/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@ package reverse_test

import (
"bytes"
"fmt"
"os"
"testing"

"github.com/rfjakob/gocryptfs/tests/test_helpers"
)

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

Expand All @@ -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"
Expand All @@ -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)
}
}
Expand Down
29 changes: 16 additions & 13 deletions tests/reverse/one_file_system_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package reverse
package reverse_test

import (
"io/ioutil"
"net/url"
"os"
"runtime"
"syscall"
"testing"

"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)
Expand All @@ -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)
Expand Down Expand Up @@ -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) })
}

0 comments on commit fbccb16

Please sign in to comment.