//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" "slices" "strings" "hakurei.app/test/internal/testsuite" ) // checkBadOpts invokes cmd/sharefs with the specified options and compares // the resulting error message. func checkBadOpts(username, opts, want string) { var buf strings.Builder buf.Grow(len(want)) sudo := []string{"sudo", "-u", username, "-i", "--"} if username == "root" { sudo = nil } a := slices.Concat(sudo, []string{ "sharefs", "-f", "-o", "source=/etc," + opts, "/mnt", }) cmd := exec.Command(a[0], a[1:]...) 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() username := testsuite.GetUser().Username if err := os.Mkdir("result", 0755); err != nil { log.Fatal(err) } done := make(chan struct{}) go func() { defer close(done) testsuite.MustRun( "fs_mark", "-v", "-d", "/sdcard/fs_mark", "-l", "result/fs_mark.log", ) }() log.Println("checking malformed setuid/setgid representation") checkBadOpts(username, "setuid=ff", "sharefs: invalid value for option setuid\n") checkBadOpts(username, "setgid=ff", "sharefs: invalid value for option setgid\n") log.Println("checking bounds check for setuid/setgid") checkBadOpts(username, "setuid=0", "sharefs: invalid value for option setuid\n") checkBadOpts(username, "setgid=0", "sharefs: invalid value for option setgid\n") checkBadOpts(username, "setuid=-1", "sharefs: invalid value for option setuid\n") checkBadOpts(username, "setgid=-1", "sharefs: invalid value for option setgid\n") log.Println("checking non-root setuid/setgid") checkBadOpts(username, "setuid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") checkBadOpts(username, "setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") checkBadOpts(username, "setuid=1023,setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") checkBadOpts(username, "mkdir", "sharefs: mkdir has no effect when not starting as root\n") log.Println("checking root without setuid/setgid") checkBadOpts("root", "allow_other", "sharefs: setuid and setgid must not be 0\n") checkBadOpts("root", "setuid=1023", "sharefs: setuid and setgid must not be 0\n") checkBadOpts("root", "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.MustRunAs(username, "-i", "mkdir", "/tmp/sdcard", "/tmp/persistent") testsuite.MustRunAs(username, "-i", "sharefs", "-o", "source=/tmp/persistent", "/tmp/sdcard") testsuite.MustRunAs(username, "-i", "touch", "/tmp/sdcard/check") testsuite.MustRunAs(username, "-i", "umount", "/tmp/sdcard") testsuite.MustRunAs(username, "-i", "rm", "/tmp/persistent/check") testsuite.MustRunAs(username, "-i", "rmdir", "/tmp/sdcard", "/tmp/persistent") log.Println("waiting for fs_mark to complete") <-done const ( backingDir = "/var/lib/sdcard" sharefsUser = "media_rw" ) log.Println("checking permissions") testsuite.MustRunAs(sharefsUser, "touch", backingDir+"/fs_mark/.check") testsuite.MustRunAs(sharefsUser, "rm", backingDir+"/fs_mark/.check") testsuite.MustRunAs(username, "-i", "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) } }