From 8527b8ef9b00c72b1a8e30e5917c7bdd3c0e79ef Mon Sep 17 00:00:00 2001 From: Jess Frazelle Date: Wed, 18 May 2016 18:47:24 -0700 Subject: [PATCH] syscall: add Unshare flags to SysProcAttr on Linux This patch adds Unshare flags to SysProcAttr for Linux systems. Fixes #1954 Change-Id: Id819c3f92b1474e5a06dd8d55f89d74a43eb770c Reviewed-on: https://go-review.googlesource.com/23233 Run-TryBot: Ian Lance Taylor TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor --- src/syscall/exec_linux.go | 9 +++++++++ src/syscall/exec_linux_test.go | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/src/syscall/exec_linux.go b/src/syscall/exec_linux.go index e49bad75b2..5a6b204997 100644 --- a/src/syscall/exec_linux.go +++ b/src/syscall/exec_linux.go @@ -32,6 +32,7 @@ type SysProcAttr struct { 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. @@ -194,6 +195,14 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } + // 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)) diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go index eb32cfd4b1..ec5be107e0 100644 --- a/src/syscall/exec_linux_test.go +++ b/src/syscall/exec_linux_test.go @@ -125,3 +125,39 @@ 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") + } + + 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)) + } +} -- 2.50.0