aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xtest.bash3
-rw-r--r--tests/cli/cli_test.go33
-rw-r--r--tests/root_test/root_test.go178
3 files changed, 203 insertions, 11 deletions
diff --git a/test.bash b/test.bash
index 266a875..091f0ac 100755
--- a/test.bash
+++ b/test.bash
@@ -85,8 +85,7 @@ if grep -R "panic(" ./*.go internal ; then
fi
# All functions from the commit msg in https://go-review.googlesource.com/c/go/+/210639
-if grep -R -E 'syscall.(Setegid|Seteuid|Setgroups|Setgid|Setregid|Setreuid|Setresgid|Setresuid|Setuid)\(' \
- ./*.go internal ; then
+if find . -type f -name \*.go -print0 | xargs -0 grep -E 'syscall.(Setegid|Seteuid|Setgroups|Setgid|Setregid|Setreuid|Setresgid|Setresuid|Setuid)\(' ; then
echo "$MYNAME: You probably want to use unix.Setgroups and friends. See the comments in OpenatUser() for why."
exit 1
fi
diff --git a/tests/cli/cli_test.go b/tests/cli/cli_test.go
index 23cea05..9d25062 100644
--- a/tests/cli/cli_test.go
+++ b/tests/cli/cli_test.go
@@ -9,6 +9,7 @@ import (
"os/exec"
"strconv"
"strings"
+ "sync"
"syscall"
"testing"
"time"
@@ -869,3 +870,35 @@ func TestSharedstorage(t *testing.T) {
t.Fatal(st2.Size)
}
}
+
+// Test that the filesystem is immediately ready for Creat() after mount returns
+func TestMountCreat(t *testing.T) {
+ const concurrency = 2
+ const repeat = 2
+
+ dir := test_helpers.InitFS(t)
+ mnt := dir + ".mnt"
+ err := os.Mkdir(mnt, 0700)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ for j := 0; j < repeat; j++ {
+ test_helpers.MountOrFatal(t, dir, mnt, "-extpass=echo test")
+ var wg sync.WaitGroup
+ wg.Add(concurrency)
+ for i := 0; i < concurrency; i++ {
+ go func(i int) {
+ path := fmt.Sprintf("%s/%d", mnt, i)
+ fd, err := syscall.Creat(path, 0600)
+ syscall.Close(fd)
+ if err != nil {
+ t.Errorf("Creat %q: %v", path, err)
+ }
+ wg.Done()
+ }(i)
+ }
+ wg.Wait()
+ test_helpers.UnmountPanic(mnt)
+ }
+}
diff --git a/tests/root_test/root_test.go b/tests/root_test/root_test.go
index 26caafc..079c03b 100644
--- a/tests/root_test/root_test.go
+++ b/tests/root_test/root_test.go
@@ -1,11 +1,19 @@
+// Package root_test contains tests that need root
+// permissions to run
package root_test
import (
+ "io/ioutil"
"os"
+ "os/exec"
+ "path/filepath"
"runtime"
+ "sync"
"syscall"
"testing"
+ "golang.org/x/sys/unix"
+
"github.com/rfjakob/gocryptfs/tests/test_helpers"
)
@@ -13,25 +21,57 @@ func asUser(uid int, gid int, supplementaryGroups []int, f func() error) error {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
- err := syscall.Setgroups(supplementaryGroups)
+ err := unix.Setgroups(supplementaryGroups)
if err != nil {
return err
}
- defer syscall.Setgroups(nil)
-
- err = syscall.Setregid(-1, gid)
+ defer func() {
+ err = unix.Setgroups(nil)
+ if err != nil {
+ panic(err)
+ }
+ }()
+ err = unix.Setregid(-1, gid)
if err != nil {
return err
}
- defer syscall.Setregid(-1, 0)
-
- err = syscall.Setreuid(-1, uid)
+ defer func() {
+ err = unix.Setregid(-1, 0)
+ if err != nil {
+ panic(err)
+ }
+ }()
+ err = unix.Setreuid(-1, uid)
if err != nil {
return err
}
- defer syscall.Setreuid(-1, 0)
+ defer func() {
+ err = unix.Setreuid(-1, 0)
+ if err != nil {
+ panic(err)
+ }
+ }()
+
+ ret := f()
- return f()
+ // Also reset the saved user id (suid) and saved group id (sgid) to prevent
+ // bizarre failures in later tests.
+ //
+ // Yes, the kernel checks that *all of them* match:
+ // https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/fuse/dir.c?h=v5.12-rc2#n1193
+ //
+ // How to check:
+ // ps -o tid,pid,euid,ruid,suid,egid,rgid,sgid,cmd -eL
+ err = unix.Setresuid(0, 0, 0)
+ if err != nil {
+ panic(err)
+ }
+ err = unix.Setresgid(0, 0, 0)
+ if err != nil {
+ panic(err)
+ }
+
+ return ret
}
func TestSupplementaryGroups(t *testing.T) {
@@ -73,3 +113,123 @@ func TestSupplementaryGroups(t *testing.T) {
t.Error(err)
}
}
+
+func writeTillFull(t *testing.T, path string) (int, syscall.Errno) {
+ runtime.LockOSThread()
+ defer runtime.UnlockOSThread()
+
+ fd, err := syscall.Creat(path, 0600)
+ if err != nil {
+ return 0, err.(syscall.Errno)
+ }
+ defer syscall.Close(fd)
+ // Write in 100.000 byte-blocks, which is not aligend to the
+ // underlying block size
+ buf := make([]byte, 100000)
+ var sz int
+ for {
+ n, err := syscall.Write(fd, buf)
+ if err != nil {
+ return sz, err.(syscall.Errno)
+ }
+ sz += n
+ }
+ return sz, 0
+}
+
+func TestDiskFull(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("must run as root")
+ }
+
+ // Create 10 MB file full of zeros
+ ext4img := filepath.Join(test_helpers.TmpDir, t.Name()+".ext4")
+ f, err := os.Create(ext4img)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ err = f.Truncate(10 * 1024 * 1024)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Format as ext4
+ cmd := exec.Command("mkfs.ext4", ext4img)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Log(string(out))
+ t.Fatal(err)
+ }
+
+ // Mount ext4
+ ext4mnt := ext4img + ".mnt"
+ err = os.Mkdir(ext4mnt, 0600)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cmd = exec.Command("mount", ext4img, ext4mnt)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Log(string(out))
+ t.Fatal(err)
+ }
+ defer syscall.Unlink(ext4img)
+ defer syscall.Unmount(ext4mnt, 0)
+
+ // gocryptfs -init
+ cipherdir := ext4mnt + "/a"
+ if err = os.Mkdir(cipherdir, 0600); err != nil {
+ t.Fatal(err)
+ }
+ cmd = exec.Command(test_helpers.GocryptfsBinary, "-q", "-init", "-extpass", "echo test", "-scryptn=10", cipherdir)
+ out, err = cmd.CombinedOutput()
+ if err != nil {
+ t.Log(string(out))
+ t.Fatal(err)
+ }
+
+ // Mount gocryptfs
+ mnt := ext4mnt + "/b"
+ err = os.Mkdir(mnt, 0600)
+ if err != nil {
+ t.Fatal(err)
+ }
+ test_helpers.MountOrFatal(t, cipherdir, mnt, "-extpass", "echo test")
+ defer test_helpers.UnmountPanic(mnt)
+
+ // Write till we get ENOSPC
+ var err1, err2 error
+ var sz1, sz2 int
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ sz1, err1 = writeTillFull(t, mnt+"/foo1")
+ wg.Done()
+ }()
+ go func() {
+ sz2, err2 = writeTillFull(t, mnt+"/foo2")
+ wg.Done()
+ }()
+ wg.Wait()
+ if err1 != syscall.ENOSPC || err2 != syscall.ENOSPC {
+ t.Fatalf("err1=%v, err2=%v", err1, err2)
+ }
+ t.Logf("sz1=%d, sz2=%d", sz1, sz2)
+
+ foo1, err := ioutil.ReadFile(mnt + "/foo1")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(foo1) != sz1 {
+ t.Fail()
+ }
+
+ foo2, err := ioutil.ReadFile(mnt + "/foo2")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(foo2) != sz2 {
+ t.Fail()
+ }
+}