Pgid int // Child's process group ID if Setpgid.
Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
Cloneflags uintptr // Flags for clone calls (Linux only)
+ Unshare uintptr // Flags for unshare calls (Linux only)
UidMappings []SysProcIDMap // User ID mappings for user namespaces.
GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
// GidMappingsEnableSetgroups enabling setgroups syscall.
}
}
+ // Unshare
+ if sys.Unshare != 0 {
+ _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshare, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
// User and groups
if cred := sys.Credential; cred != nil {
ngroups := uintptr(len(cred.Groups))
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")
+ }
+
+ cmd := exec.Command("ip", "a")
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Unshare: 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) != 2 {
+ t.Fatalf("Expected 2 lines of output, got %d", len(lines))
+ }
+}