aboutsummaryrefslogtreecommitdiff
path: root/tests/root_test/issue893_test.go
blob: 6ad8e6d36d8b886cfdc35a0e3e8e14df5d2cead3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//go:build linux

package root_test

import (
	"fmt"
	"io/ioutil"
	"os"
	"sync"
	"syscall"
	"testing"
	"time"

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

// gocryptfs v2.5.0 upgraded x/sys/unix and we found out that, since
// https://github.com/golang/sys/commit/d0df966e6959f00dc1c74363e537872647352d51 ,
// unix.Setreuid() and friends now affect the whole process instead of only the
// current thread, breaking allow_other: https://github.com/rfjakob/gocryptfs/issues/893
//
// Let's not have this happen again by testing it here.
func TestConcurrentUserOps(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("must run as root")
	}

	var wg sync.WaitGroup

	oneStressor := func(tid int) {
		defer wg.Done()
		err := asUser(10000+tid, 20000+tid, nil, func() (err error) {
			for i := 0; i < 100; i++ {
				d := fmt.Sprintf("%s/tid%d.i%d/foo/bar/baz", test_helpers.DefaultPlainDir, tid, i)
				if err = os.MkdirAll(d, 0700); err != nil {
					return
				}
				if err = ioutil.WriteFile(d+"/foo", nil, 0400); err != nil {
					return
				}
				if err = ioutil.WriteFile(d+"/bar", []byte("aaaaaaaaaaaaaaaaaaaaa"), 0400); err != nil {
					return
				}
				if err = syscall.Unlink(d + "/foo"); err != nil {
					return
				}
				if err = os.Mkdir(d+"/foo", 0700); err != nil {
					return
				}
			}
			return nil
		})
		if err != nil {
			t.Error(err)
		}
	}

	threads := 4
	wg.Add(threads)
	for tid := 0; tid < threads; tid++ {
		go oneStressor(tid)
	}
	wg.Wait()
}

// Test that our root_test.asUser function works as expected under concurrency by
// similating a long-runnig operation with sleep(10ms).
// https://github.com/rfjakob/gocryptfs/issues/893
func TestAsUserSleep(t *testing.T) {
	if os.Getuid() != 0 {
		t.Skip("must run as root")
	}

	var wg sync.WaitGroup
	f := func(euid_want int) error {
		euid_have := syscall.Geteuid()
		if euid_want != euid_have {
			return fmt.Errorf("wrong euid: want=%d have=%d", euid_want, euid_have)
		}
		time.Sleep(10 * time.Millisecond)
		euid_have2 := syscall.Geteuid()
		if euid_want != euid_have2 {
			return fmt.Errorf("wrong euid: want=%d have2=%d", euid_want, euid_have2)
		}
		return nil
	}
	threads := 100
	wg.Add(threads)
	for i := 0; i < threads; i++ {
		go func(i int) {
			defer wg.Done()
			err := asUser(10000+i, 20000+i, nil, func() error { return f(10000 + i) })
			if err != nil {
				t.Error(err)
			}
		}(i)
	}
	wg.Wait()
}