From 527b6bbac1669c81581fcb74d565745f22b4d512 Mon Sep 17 00:00:00 2001 From: Dmitri Shuralyov Date: Thu, 7 Sep 2023 20:21:44 -0400 Subject: [PATCH] syscall: skip unshare tests if mount syscall is not available CL 513779 added crude skips for tests that couldn't work when run under 'unshare --net --map-root-user' as used by the current iteration of the no-network check in LUCI. Bryan suggested a more targeted way to detect when the environment is insufficient, which makes it possible to remove the builder-specific skip and its slightly incorrect explaining comment. Updates #30612. Change-Id: I0de79f44ab94d7f1018384c2e959ca7df3a1b0ae Cq-Include-Trybots: luci.golang.try:gotip-linux-amd64-longtest,gotip-linux-amd64-longtest-race Reviewed-on: https://go-review.googlesource.com/c/go/+/526835 Run-TryBot: Dmitri Shuralyov Auto-Submit: Dmitri Shuralyov Reviewed-by: Dmitri Shuralyov LUCI-TryBot-Result: Go LUCI TryBot-Result: Gopher Robot Reviewed-by: Bryan Mills --- src/syscall/exec_linux_test.go | 47 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index 7883096b88..e1b322ae62 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -218,18 +218,20 @@ func TestGroupCleanupUserNamespace(t *testing.T) { // Test for https://go.dev/issue/19661: unshare fails because systemd // has forced / to be shared func TestUnshareMountNameSpace(t *testing.T) { - testenv.MustHaveExec(t) - + const mountNotSupported = "mount is not supported: " // Output prefix indicatating a test skip. if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { dir := flag.Args()[0] err := syscall.Mount("none", dir, "proc", 0, "") - if err != nil { - fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %#v", dir, err) + if testenv.SyscallIsNotSupported(err) { + fmt.Print(mountNotSupported, err) + } else if err != nil { + fmt.Fprintf(os.Stderr, "unshare: mount %s: %v\n", dir, err) os.Exit(2) } os.Exit(0) } + testenv.MustHaveExec(t) exe, err := os.Executable() if err != nil { t.Fatal(err) @@ -247,20 +249,17 @@ func TestUnshareMountNameSpace(t *testing.T) { cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1") cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS} - o, err := cmd.CombinedOutput() + out, err := cmd.CombinedOutput() if err != nil { if testenv.SyscallIsNotSupported(err) { t.Skipf("skipping: could not start process with CLONE_NEWNS: %v", err) } - if testing.Short() && testenv.Builder() != "" && os.Getenv("USER") == "swarming" { - // The Go build system's swarming user is known not to support - // starting a process with CLONE_NEWNS. - // Unfortunately, it doesn't get recognized as such due the current - // implementation of a no-network check using 'unshare -n -r'. - // Since this test does need start this process, we need to skip it. - t.Skipf("skipping: could not start process with CLONE_NEWNS: %v", err) + t.Fatalf("unshare failed: %v\n%s", err, out) + } else if len(out) != 0 { + if bytes.HasPrefix(out, []byte(mountNotSupported)) { + t.Skipf("skipping: helper process reported %s", out) } - t.Fatalf("unshare failed: %v\n%s", err, o) + t.Fatalf("unexpected output from helper process: %s", out) } // How do we tell if the namespace was really unshared? It turns out @@ -273,11 +272,14 @@ func TestUnshareMountNameSpace(t *testing.T) { // Test for Issue 20103: unshare fails when chroot is used func TestUnshareMountNameSpaceChroot(t *testing.T) { + const mountNotSupported = "mount is not supported: " // Output prefix indicatating a test skip. if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { dir := flag.Args()[0] err := syscall.Mount("none", dir, "proc", 0, "") - if err != nil { - fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %#v", dir, err) + if testenv.SyscallIsNotSupported(err) { + fmt.Print(mountNotSupported, err) + } else if err != nil { + fmt.Fprintf(os.Stderr, "unshare: mount %s: %v\n", dir, err) os.Exit(2) } os.Exit(0) @@ -310,20 +312,17 @@ func TestUnshareMountNameSpaceChroot(t *testing.T) { cmd.Env = append(cmd.Environ(), "GO_WANT_HELPER_PROCESS=1") cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: d, Unshareflags: syscall.CLONE_NEWNS} - o, err := cmd.CombinedOutput() + out, err := cmd.CombinedOutput() if err != nil { if testenv.SyscallIsNotSupported(err) { t.Skipf("skipping: could not start process with CLONE_NEWNS and Chroot %q: %v", d, err) } - if testing.Short() && testenv.Builder() != "" && os.Getenv("USER") == "swarming" { - // The Go build system's swarming user is known not to support - // starting a process with CLONE_NEWNS and Chroot. - // Unfortunately, it doesn't get recognized as such due the current - // implementation of a no-network check using 'unshare -n -r'. - // Since this test does need start this process, we need to skip it. - t.Skipf("skipping: could not start process with CLONE_NEWNS and Chroot %q: %v", d, err) + t.Fatalf("unshare failed: %v\n%s", err, out) + } else if len(out) != 0 { + if bytes.HasPrefix(out, []byte(mountNotSupported)) { + t.Skipf("skipping: helper process reported %s", out) } - t.Fatalf("unshare failed: %v\n%s", err, o) + t.Fatalf("unexpected output from helper process: %s", out) } // How do we tell if the namespace was really unshared? It turns out -- 2.50.0