90687215a4
Fixes https://github.com/rfjakob/gocryptfs/issues/168 Steps to reproduce the problem: * Create a regular reverse mount point * Create files with the same very long name in multiple directories - so far everything works as expected, and it will appear with a different name each time, for example, gocryptfs.longname.A in directory A and gocryptfs.longname.B in directory B * Try to access a path with A/gocryptfs.longname.B or B/gocryptfs.longname.A - this should fail, but it actually works. The problem is that the longname cache only uses the path as key and not the dir or divIV. Assume an attacker can directly interact with a reverse mount and knows the relation longname path -> unencoded path in one directory, it allows to test if the same unencoded filename appears in any other directory.
88 lines
3.7 KiB
Go
88 lines
3.7 KiB
Go
package reverse_test
|
|
|
|
import (
|
|
"io/ioutil"
|
|
"testing"
|
|
|
|
"github.com/rfjakob/gocryptfs/internal/ctlsock"
|
|
"github.com/rfjakob/gocryptfs/tests/test_helpers"
|
|
)
|
|
|
|
var ctlSockTestCases = [][]string{
|
|
{"4RQq1dJlfvQPaVU5Xypf0w==", "file"},
|
|
{"gocryptfs.longname.ZQCAoi5li3xvDZRO8McBV0L_kzJc4IcAOEzuW-2S1Y4=", "longfile." + x240},
|
|
{"v6puXntoQOk7Mhl8zJ4Idg==", "dir"},
|
|
{"v6puXntoQOk7Mhl8zJ4Idg==/UVy2gV0RQTUC8AE4wYoMwg==", "dir/file"},
|
|
{"v6puXntoQOk7Mhl8zJ4Idg==/fvHFLHlxHCQ7EpVMJu0AZg==", "dir/dir"},
|
|
{"v6puXntoQOk7Mhl8zJ4Idg==/fvHFLHlxHCQ7EpVMJu0AZg==/_4uudIGniACke55JoDsqDA==", "dir/dir/dir"},
|
|
{"v6puXntoQOk7Mhl8zJ4Idg==/fvHFLHlxHCQ7EpVMJu0AZg==/QvPahkkeVRKTw2kdZFZxwQ==", "dir/dir/file"},
|
|
{"v6puXntoQOk7Mhl8zJ4Idg==/gocryptfs.longname.y6rxCn6Id8hIZL2t_STpdLZpu-aE2HpprJR25xD60mk=", "dir/longfile." + x240},
|
|
{"gocryptfs.longname.cvRximo1ATRJVEzw_V9MZieHFlod9y2iv2Sug1kbiTE=", "longdir." + x240},
|
|
{"gocryptfs.longname.cvRximo1ATRJVEzw_V9MZieHFlod9y2iv2Sug1kbiTE=/-LMdFgFt6UxO-z5iJvuC9w==", "longdir." + x240 + "/dir"},
|
|
{"gocryptfs.longname.cvRximo1ATRJVEzw_V9MZieHFlod9y2iv2Sug1kbiTE=/rBPJYAzcHWLdPj1T8kgh8A==", "longdir." + x240 + "/file"},
|
|
}
|
|
|
|
// Test DecryptPath and EncryptPath
|
|
func TestCtlSockPathOps(t *testing.T) {
|
|
if plaintextnames {
|
|
t.Skip("this only tests encrypted names")
|
|
}
|
|
mnt, err := ioutil.TempDir(test_helpers.TmpDir, "reverse_mnt_")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sock := mnt + ".sock"
|
|
test_helpers.MountOrFatal(t, "ctlsock_reverse_test_fs", mnt, "-reverse", "-extpass", "echo test", "-ctlsock="+sock)
|
|
defer test_helpers.UnmountPanic(mnt)
|
|
var req ctlsock.RequestStruct
|
|
var response ctlsock.ResponseStruct
|
|
for i, tc := range ctlSockTestCases {
|
|
// Decrypt
|
|
req = ctlsock.RequestStruct{DecryptPath: tc[0]}
|
|
response = test_helpers.QueryCtlSock(t, sock, req)
|
|
if response.ErrNo != 0 {
|
|
t.Errorf("Testcase %d Decrypt: %q ErrNo=%d ErrText=%s", i, tc[0], response.ErrNo, response.ErrText)
|
|
} else if response.Result != tc[1] {
|
|
t.Errorf("Testcase %d Decrypt: Want %q got %q", i, tc[1], response.Result)
|
|
}
|
|
// Encrypt
|
|
req = ctlsock.RequestStruct{EncryptPath: tc[1]}
|
|
response = test_helpers.QueryCtlSock(t, sock, req)
|
|
if response.ErrNo != 0 {
|
|
t.Errorf("Testcase %d Encrypt: %q ErrNo=%d ErrText=%s", i, tc[0], response.ErrNo, response.ErrText)
|
|
} else if response.Result != tc[0] {
|
|
t.Errorf("Testcase %d Encrypt: Want %q got %q", i, tc[1], response.Result)
|
|
}
|
|
}
|
|
// At this point the longname parent cache should be populated.
|
|
// Check that we do not mix up information for different directories.
|
|
req = ctlsock.RequestStruct{DecryptPath: "gocryptfs.longname.y6rxCn6Id8hIZL2t_STpdLZpu-aE2HpprJR25xD60mk="}
|
|
response = test_helpers.QueryCtlSock(t, sock, req)
|
|
if response.ErrNo != -1 {
|
|
t.Errorf("File should not exist: ErrNo=%d ErrText=%s", response.ErrNo, response.ErrText)
|
|
}
|
|
req = ctlsock.RequestStruct{DecryptPath: "v6puXntoQOk7Mhl8zJ4Idg==/gocryptfs.longname.ZQCAoi5li3xvDZRO8McBV0L_kzJc4IcAOEzuW-2S1Y4="}
|
|
response = test_helpers.QueryCtlSock(t, sock, req)
|
|
if response.ErrNo != -1 {
|
|
t.Errorf("File should not exist: ErrNo=%d ErrText=%s", response.ErrNo, response.ErrText)
|
|
}
|
|
}
|
|
|
|
// We should not panic when somebody feeds requests that make no sense
|
|
func TestCtlSockCrash(t *testing.T) {
|
|
if plaintextnames {
|
|
t.Skip("this only tests encrypted names")
|
|
}
|
|
mnt, err := ioutil.TempDir(test_helpers.TmpDir, "reverse_mnt_")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
sock := mnt + ".sock"
|
|
test_helpers.MountOrFatal(t, "ctlsock_reverse_test_fs", mnt, "-reverse", "-extpass", "echo test", "-ctlsock="+sock,
|
|
"-wpanic=0", "-nosyslog=0")
|
|
defer test_helpers.UnmountPanic(mnt)
|
|
// Try to crash it
|
|
req := ctlsock.RequestStruct{DecryptPath: "gocryptfs.longname.XXX_TestCtlSockCrash_XXX.name"}
|
|
test_helpers.QueryCtlSock(t, sock, req)
|
|
}
|