diff options
Diffstat (limited to 'test/sharefs')
| -rw-r--r-- | test/sharefs/configuration.nix | 44 | ||||
| -rw-r--r-- | test/sharefs/default.nix | 44 | ||||
| -rw-r--r-- | test/sharefs/main.go | 126 | ||||
| -rw-r--r-- | test/sharefs/test.py | 60 |
4 files changed, 126 insertions, 148 deletions
diff --git a/test/sharefs/configuration.nix b/test/sharefs/configuration.nix deleted file mode 100644 index 05d67dcb..00000000 --- a/test/sharefs/configuration.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ pkgs, ... }: -{ - users.users = { - alice = { - isNormalUser = true; - description = "Alice Foobar"; - password = "foobar"; - uid = 1000; - }; - }; - - home-manager.users.alice.home.stateVersion = "24.11"; - - # Automatically login on tty1 as a normal user: - services.getty.autologinUser = "alice"; - - environment = { - # For benchmarking sharefs: - systemPackages = [ pkgs.fsmark ]; - }; - - virtualisation = { - # Hopefully reduces spurious test failures: - memorySize = if pkgs.stdenv.hostPlatform.is32bit then 2046 else 8192; - - diskSize = 6 * 1024; - - qemu.options = [ - # Increase test performance: - "-smp 16" - ]; - }; - - environment.hakurei = rec { - enable = true; - stateDir = "/var/lib/hakurei"; - sharefs.source = "${stateDir}/sdcard"; - users.alice = 0; - - extraHomeConfig = { - home.stateVersion = "23.05"; - }; - }; -} diff --git a/test/sharefs/default.nix b/test/sharefs/default.nix deleted file mode 100644 index e963eaa6..00000000 --- a/test/sharefs/default.nix +++ /dev/null @@ -1,44 +0,0 @@ -{ - testers, - - system, - self, -}: -testers.nixosTest { - name = "sharefs"; - nodes.machine = - { options, pkgs, ... }: - let - fhs = - let - hakurei = options.environment.hakurei.package.default; - in - pkgs.buildFHSEnv { - pname = "hakurei-fhs"; - inherit (hakurei) version; - targetPkgs = _: hakurei.targetPkgs; - extraOutputsToInstall = [ "dev" ]; - profile = '' - export PKG_CONFIG_PATH="/usr/share/pkgconfig:$PKG_CONFIG_PATH" - ''; - }; - in - { - environment.systemPackages = [ - # For go tests: - (pkgs.writeShellScriptBin "sharefs-workload-hakurei-tests" '' - cp -r "${self.packages.${system}.hakurei.src}" "/sdcard/hakurei" && cd "/sdcard/hakurei" - ${fhs}/bin/hakurei-fhs -c 'ROSA_SKIP_BINFMT=1 CC="clang -O3 -Werror" go test ./...' - '') - ]; - - imports = [ - ./configuration.nix - - self.nixosModules.hakurei - self.inputs.home-manager.nixosModules.home-manager - ]; - }; - - testScript = builtins.readFile ./test.py; -} diff --git a/test/sharefs/main.go b/test/sharefs/main.go new file mode 100644 index 00000000..536a61b3 --- /dev/null +++ b/test/sharefs/main.go @@ -0,0 +1,126 @@ +//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() + + if err := os.Mkdir("result", 0755); err != nil { + log.Fatal(err) + } + + if len(os.Args) != 2 { + log.Fatal("expecting 1 argument") + } + username := os.Args[1] + + 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) + } +} diff --git a/test/sharefs/test.py b/test/sharefs/test.py deleted file mode 100644 index 4b925c9c..00000000 --- a/test/sharefs/test.py +++ /dev/null @@ -1,60 +0,0 @@ -start_all() -machine.wait_for_unit("multi-user.target") - -# To check sharefs version: -print(machine.succeed("sharefs -V")) - -# Make sure sharefs started: -machine.wait_for_unit("sdcard.mount") - -machine.succeed("mkdir /mnt") -def check_bad_opts_output(opts, want, source="/etc", privileged=False): - output = machine.fail(("" if privileged else "sudo -u alice -i ") + f"sharefs -f -o source={source},{opts} /mnt 2>&1") - if output != want: - raise Exception(f"unexpected output: {output}") - -# Malformed setuid/setgid representation: -check_bad_opts_output("setuid=ff", "sharefs: invalid value for option setuid\n") -check_bad_opts_output("setgid=ff", "sharefs: invalid value for option setgid\n") - -# Bounds check for setuid/setgid: -check_bad_opts_output("setuid=0", "sharefs: invalid value for option setuid\n") -check_bad_opts_output("setgid=0", "sharefs: invalid value for option setgid\n") -check_bad_opts_output("setuid=-1", "sharefs: invalid value for option setuid\n") -check_bad_opts_output("setgid=-1", "sharefs: invalid value for option setgid\n") - -# Non-root setuid/setgid: -check_bad_opts_output("setuid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") -check_bad_opts_output("setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") -check_bad_opts_output("setuid=1023,setgid=1023", "sharefs: setuid and setgid has no effect when not starting as root\n") -check_bad_opts_output("mkdir", "sharefs: mkdir has no effect when not starting as root\n") - -# Starting as root without setuid/setgid: -check_bad_opts_output("allow_other", "sharefs: setuid and setgid must not be 0\n", privileged=True) -check_bad_opts_output("setuid=1023", "sharefs: setuid and setgid must not be 0\n", privileged=True) -check_bad_opts_output("setgid=1023", "sharefs: setuid and setgid must not be 0\n", privileged=True) - -# Make sure nothing actually got mounted: -machine.fail("umount /mnt") -machine.succeed("rmdir /mnt") - -# Unprivileged mount/unmount: -machine.succeed("sudo -u alice -i mkdir /home/alice/{sdcard,persistent}") -machine.succeed("sudo -u alice -i sharefs -o source=/home/alice/persistent /home/alice/sdcard") -machine.succeed("sudo -u alice -i touch /home/alice/sdcard/check") -machine.succeed("sudo -u alice -i umount /home/alice/sdcard") -machine.succeed("sudo -u alice -i rm /home/alice/persistent/check") -machine.succeed("sudo -u alice -i rmdir /home/alice/{sdcard,persistent}") - -# Benchmark sharefs: -machine.succeed("fs_mark -v -d /sdcard/fs_mark -l /tmp/fs_log.txt") -machine.copy_from_vm("/tmp/fs_log.txt", "") - -# Check permissions: -machine.succeed("sudo -u sharefs touch /var/lib/hakurei/sdcard/fs_mark/.check") -machine.succeed("sudo -u sharefs rm /var/lib/hakurei/sdcard/fs_mark/.check") -machine.succeed("sudo -u alice rm -rf /sdcard/fs_mark") -machine.fail("ls /var/lib/hakurei/sdcard/fs_mark") - -# Run hakurei tests on sharefs: -machine.succeed("sudo -u alice -i sharefs-workload-hakurei-tests") |
