summaryrefslogtreecommitdiff
path: root/libgo/go/syscall/exec_linux_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/syscall/exec_linux_test.go')
-rw-r--r--libgo/go/syscall/exec_linux_test.go133
1 files changed, 132 insertions, 1 deletions
diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go
index 6d31941184..7a4b571760 100644
--- a/libgo/go/syscall/exec_linux_test.go
+++ b/libgo/go/syscall/exec_linux_test.go
@@ -26,11 +26,14 @@ func isChrooted(t *testing.T) bool {
return root.Sys().(*syscall.Stat_t).Ino != 2
}
-func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
+func checkUserNS(t *testing.T) {
if _, err := os.Stat("/proc/self/ns/user"); err != nil {
if os.IsNotExist(err) {
t.Skip("kernel doesn't support user namespaces")
}
+ if os.IsPermission(err) {
+ t.Skip("unable to test user namespaces due to permissions")
+ }
t.Fatalf("Failed to stat /proc/self/ns/user: %v", err)
}
if isChrooted(t) {
@@ -53,6 +56,10 @@ func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
}
+}
+
+func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
+ checkUserNS(t)
cmd := exec.Command("whoami")
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUSER,
@@ -122,3 +129,127 @@ func TestEmptyCredGroupsDisableSetgroups(t *testing.T) {
t.Fatal(err)
}
}
+
+func TestUnshare(t *testing.T) {
+ // Make sure we are running as root so we have permissions to use unshare
+ // and create a network namespace.
+ if os.Getuid() != 0 {
+ t.Skip("kernel prohibits unshare in unprivileged process, unless using user namespace")
+ }
+
+ // When running under the Go continuous build, skip tests for
+ // now when under Kubernetes. (where things are root but not quite)
+ // Both of these are our own environment variables.
+ // See Issue 12815.
+ if os.Getenv("GO_BUILDER_NAME") != "" && os.Getenv("IN_KUBERNETES") == "1" {
+ t.Skip("skipping test on Kubernetes-based builders; see Issue 12815")
+ }
+
+ path := "/proc/net/dev"
+ if _, err := os.Stat(path); err != nil {
+ if os.IsNotExist(err) {
+ t.Skip("kernel doesn't support proc filesystem")
+ }
+ if os.IsPermission(err) {
+ t.Skip("unable to test proc filesystem due to permissions")
+ }
+ t.Fatal(err)
+ }
+ if _, err := os.Stat("/proc/self/ns/net"); err != nil {
+ if os.IsNotExist(err) {
+ t.Skip("kernel doesn't support net namespace")
+ }
+ t.Fatal(err)
+ }
+
+ orig, err := ioutil.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ origLines := strings.Split(strings.TrimSpace(string(orig)), "\n")
+
+ cmd := exec.Command("cat", path)
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Unshareflags: syscall.CLONE_NEWNET,
+ }
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+ }
+
+ // Check there is only the local network interface
+ sout := strings.TrimSpace(string(out))
+ if !strings.Contains(sout, "lo:") {
+ t.Fatalf("Expected lo network interface to exist, got %s", sout)
+ }
+
+ lines := strings.Split(sout, "\n")
+ if len(lines) >= len(origLines) {
+ t.Fatalf("Got %d lines of output, want <%d", len(lines), len(origLines))
+ }
+}
+
+func TestGroupCleanup(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("we need root for credential")
+ }
+ cmd := exec.Command("id")
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Credential: &syscall.Credential{
+ Uid: 0,
+ Gid: 0,
+ },
+ }
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+ }
+ strOut := strings.TrimSpace(string(out))
+ expected := "uid=0(root) gid=0(root) groups=0(root)"
+ // Just check prefix because some distros reportedly output a
+ // context parameter; see https://golang.org/issue/16224.
+ if !strings.HasPrefix(strOut, expected) {
+ t.Errorf("id command output: %q, expected prefix: %q", strOut, expected)
+ }
+}
+
+func TestGroupCleanupUserNamespace(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("we need root for credential")
+ }
+ checkUserNS(t)
+ cmd := exec.Command("id")
+ uid, gid := os.Getuid(), os.Getgid()
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Cloneflags: syscall.CLONE_NEWUSER,
+ Credential: &syscall.Credential{
+ Uid: uint32(uid),
+ Gid: uint32(gid),
+ },
+ UidMappings: []syscall.SysProcIDMap{
+ {ContainerID: 0, HostID: uid, Size: 1},
+ },
+ GidMappings: []syscall.SysProcIDMap{
+ {ContainerID: 0, HostID: gid, Size: 1},
+ },
+ }
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+ }
+ strOut := strings.TrimSpace(string(out))
+
+ // Strings we've seen in the wild.
+ expected := []string{
+ "uid=0(root) gid=0(root) groups=0(root)",
+ "uid=0(root) gid=0(root) groups=0(root),65534(nobody)",
+ "uid=0(root) gid=0(root) groups=0(root),65534(nogroup)",
+ "uid=0(root) gid=0(root) groups=0(root),65534",
+ }
+ for _, e := range expected {
+ if strOut == e {
+ return
+ }
+ }
+ t.Errorf("id command output: %q, expected one of %q", strOut, expected)
+}