aboutsummaryrefslogtreecommitdiffhomepage
path: root/cmd/sharefs/testsuite/main.go
blob: 167875a10917d8b1068d530c0e1ffc3d55c81efb (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//go:build testsuite

// The sharefs test program checks cli behaviour and exercises the filesystem
// implemented by cmd/sharefs using fs_mark.
package main

import (
	"errors"
	"log"
	"os"
	"os/exec"
	"strings"
	"syscall"

	"hakurei.app/internal/testsuite"
)

// checkBadOpts invokes cmd/sharefs with the specified options and compares
// the resulting error message.
func checkBadOpts(cred *syscall.Credential, opts, want string) {
	var buf strings.Builder
	buf.Grow(len(want))

	cmd := exec.Command(
		"sharefs",
		"-f",
		"-o", "source=/etc,"+opts,
		"/mnt",
	)
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Pdeathsig:  syscall.SIGKILL,
		Credential: cred,
	}
	cmd.Stderr = &buf
	err := cmd.Run()
	if err == nil {
		log.Fatalf("opts=%q, unexpected success", opts)
	}
	if e, ok := errors.AsType[*exec.ExitError](err); !ok {
		log.Fatal(err)
	} else if !e.Exited() {
		log.Fatal(e)
	}

	if got := buf.String(); got != want {
		log.Fatalf("opts=%q\n\t got:%q\n\twant:%q", opts, got, want)
	}
}

func main() {
	go testsuite.ReceiveSignals()

	cred := syscall.Credential{Uid: 1000, Gid: 100}
	if err := os.Mkdir("result", 0755); err != nil {
		log.Fatal(err)
	}

	done := make(chan struct{})
	go func() {
		defer close(done)

		testsuite.MustRun(
			nil, nil,
			"fs_mark",
			"-v",
			"-d", "/sdcard/fs_mark",
			"-l", "result/fs_mark.log",
		)
	}()

	log.Println("checking malformed setuid/setgid representation")
	checkBadOpts(&cred, "setuid=ff", "sharefs: invalid value for option setuid\n")
	checkBadOpts(&cred, "setgid=ff", "sharefs: invalid value for option setgid\n")

	log.Println("checking bounds check for setuid/setgid")
	checkBadOpts(&cred, "setuid=0", "sharefs: invalid value for option setuid\n")
	checkBadOpts(&cred, "setgid=0", "sharefs: invalid value for option setgid\n")
	checkBadOpts(&cred, "setuid=-1", "sharefs: invalid value for option setuid\n")
	checkBadOpts(&cred, "setgid=-1", "sharefs: invalid value for option setgid\n")

	log.Println("checking non-root setuid/setgid")
	checkBadOpts(&cred, "setuid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n")
	checkBadOpts(&cred, "setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n")
	checkBadOpts(&cred, "setuid=1023,setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n")
	checkBadOpts(&cred, "mkdir", "sharefs: mkdir has no effect when not starting as root\n")

	log.Println("checking root without setuid/setgid")
	checkBadOpts(nil, "allow_other", "sharefs: setuid and setgid must not be 0\n")
	checkBadOpts(nil, "setuid=1023", "sharefs: setuid and setgid must not be 0\n")
	checkBadOpts(nil, "setgid=1023", "sharefs: setuid and setgid must not be 0\n")

	log.Println("verifying mount point")
	if err := os.Remove("/mnt"); err != nil {
		log.Fatal(err)
	}

	log.Println("checking unprivileged mount/unmount")
	testsuite.MustRun(&cred, nil, "mkdir", "/tmp/sdcard", "/tmp/persistent")
	testsuite.MustRun(&cred, nil, "sharefs", "-o", "source=/tmp/persistent", "/tmp/sdcard")
	testsuite.MustRun(&cred, nil, "touch", "/tmp/sdcard/check")
	testsuite.MustRun(&cred, nil, "umount", "/tmp/sdcard")
	testsuite.MustRun(&cred, nil, "rm", "/tmp/persistent/check")
	testsuite.MustRun(&cred, nil, "rmdir", "/tmp/sdcard", "/tmp/persistent")

	log.Println("waiting for fs_mark to complete")
	<-done

	const backingDir = "/var/lib/sdcard"
	sharefsCred := syscall.Credential{Uid: 1023, Gid: 1023}
	log.Println("checking permissions")
	testsuite.MustRun(&sharefsCred, nil, "touch", backingDir+"/fs_mark/.check")
	testsuite.MustRun(&sharefsCred, nil, "rm", backingDir+"/fs_mark/.check")
	testsuite.MustRun(&cred, nil, "rm", "-rf", "/sdcard/fs_mark")
	if _, err := os.ReadDir(backingDir + "/fs_mark"); err == nil {
		log.Fatal("fs_mark directory was not removed")
	} else if !errors.Is(err, os.ErrNotExist) {
		log.Fatal(err)
	}
}