aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/syscall
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2017-09-14 17:11:35 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-09-14 17:11:35 +0000
commitbc998d034f45d1828a8663b2eed928faf22a7d01 (patch)
tree8d262a22ca7318f4bcd64269fe8fe9e45bcf8d0f /libgo/go/syscall
parenta41a6142df74219f596e612d3a7775f68ca6e96f (diff)
downloadgcc-bc998d034f45d1828a8663b2eed928faf22a7d01.zip
gcc-bc998d034f45d1828a8663b2eed928faf22a7d01.tar.gz
gcc-bc998d034f45d1828a8663b2eed928faf22a7d01.tar.bz2
libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753 From-SVN: r252767
Diffstat (limited to 'libgo/go/syscall')
-rw-r--r--libgo/go/syscall/errors_plan9.go1
-rw-r--r--libgo/go/syscall/exec_bsd.go42
-rw-r--r--libgo/go/syscall/exec_freebsd.go25
-rw-r--r--libgo/go/syscall/exec_linux.go149
-rw-r--r--libgo/go/syscall/exec_linux_test.go305
-rw-r--r--libgo/go/syscall/exec_unix.go18
-rw-r--r--libgo/go/syscall/forkpipe_bsd.go20
-rw-r--r--libgo/go/syscall/net.go34
-rw-r--r--libgo/go/syscall/syscall.go13
-rw-r--r--libgo/go/syscall/syscall_dragonfly.go4
-rw-r--r--libgo/go/syscall/syscall_linux_386.go4
-rw-r--r--libgo/go/syscall/syscall_linux_amd64.go2
-rw-r--r--libgo/go/syscall/syscall_linux_mipsx.go4
-rw-r--r--libgo/go/syscall/syscall_linux_s390x.go4
-rw-r--r--libgo/go/syscall/syscall_unix_test.go8
15 files changed, 553 insertions, 80 deletions
diff --git a/libgo/go/syscall/errors_plan9.go b/libgo/go/syscall/errors_plan9.go
index 6952562..74a5659 100644
--- a/libgo/go/syscall/errors_plan9.go
+++ b/libgo/go/syscall/errors_plan9.go
@@ -45,6 +45,7 @@ var (
// what package os and others expect.
EACCES = NewError("access permission denied")
EAFNOSUPPORT = NewError("address family not supported by protocol")
+ ESPIPE = NewError("illegal seek")
)
// Notes
diff --git a/libgo/go/syscall/exec_bsd.go b/libgo/go/syscall/exec_bsd.go
index 80991ec..9115cf0 100644
--- a/libgo/go/syscall/exec_bsd.go
+++ b/libgo/go/syscall/exec_bsd.go
@@ -26,6 +26,7 @@ type SysProcAttr struct {
// Implemented in runtime package.
func runtime_BeforeFork()
func runtime_AfterFork()
+func runtime_AfterForkInChild()
// Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
// If a dup or exec fails, write the errno error to pipe.
@@ -77,6 +78,8 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Fork succeeded, now in child.
+ runtime_AfterForkInChild()
+
// Enable tracing if requested.
if sys.Ptrace {
err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil)
@@ -126,27 +129,24 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// User and groups
if cred := sys.Credential; cred != nil {
ngroups := len(cred.Groups)
- if ngroups == 0 {
- err2 := setgroups(0, nil)
- if err2 == nil {
- err1 = 0
- } else {
- err1 = err2.(Errno)
- }
- } else {
- groups := make([]Gid_t, ngroups)
+ var groups *Gid_t
+ if ngroups > 0 {
+ gids := make([]Gid_t, ngroups)
for i, v := range cred.Groups {
- groups[i] = Gid_t(v)
+ gids[i] = Gid_t(v)
}
- err2 := setgroups(ngroups, &groups[0])
+ groups = &gids[0]
+ }
+ if !cred.NoSetGroups {
+ err2 := setgroups(ngroups, groups)
if err2 == nil {
err1 = 0
} else {
err1 = err2.(Errno)
}
- }
- if err1 != 0 {
- goto childerror
+ if err1 != 0 {
+ goto childerror
+ }
}
err2 := Setgid(int(cred.Gid))
if err2 != nil {
@@ -255,17 +255,3 @@ childerror:
raw_exit(253)
}
}
-
-// Try to open a pipe with O_CLOEXEC set on both file descriptors.
-func forkExecPipe(p []int) error {
- err := Pipe(p)
- if err != nil {
- return err
- }
- _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
- if err != nil {
- return err
- }
- _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
- return err
-}
diff --git a/libgo/go/syscall/exec_freebsd.go b/libgo/go/syscall/exec_freebsd.go
new file mode 100644
index 0000000..4ed32c0
--- /dev/null
+++ b/libgo/go/syscall/exec_freebsd.go
@@ -0,0 +1,25 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+func forkExecPipe(p []int) error {
+ err := Pipe2(p, O_CLOEXEC)
+ if err == nil {
+ return nil
+ }
+
+ // FreeBSD 9 fallback.
+ // TODO: remove this for Go 1.10 per Issue 19072
+ err = Pipe(p)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
+ return err
+}
diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go
index 8d6467a..6e2f83e 100644
--- a/libgo/go/syscall/exec_linux.go
+++ b/libgo/go/syscall/exec_linux.go
@@ -13,6 +13,12 @@ import (
//sysnb raw_prctl(option int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err Errno)
//prctl(option _C_int, arg2 _C_long, arg3 _C_long, arg4 _C_long, arg5 _C_long) _C_int
+//sysnb rawUnshare(flags int) (err Errno)
+//unshare(flags _C_int) _C_int
+
+//sysnb rawMount(source *byte, target *byte, fstype *byte, flags uintptr, data *byte) (err Errno)
+//mount(source *byte, target *byte, fstype *byte, flags _C_long, data *byte) _C_int
+
// SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux.
// See user_namespaces(7).
type SysProcIDMap struct {
@@ -42,11 +48,18 @@ type SysProcAttr struct {
// This parameter is no-op if GidMappings == nil. Otherwise for unprivileged
// users this should be set to false for mappings work.
GidMappingsEnableSetgroups bool
+ AmbientCaps []uintptr // Ambient capabilities (Linux only)
}
+var (
+ none = [...]byte{'n', 'o', 'n', 'e', 0}
+ slash = [...]byte{'/', 0}
+)
+
// Implemented in runtime package.
func runtime_BeforeFork()
func runtime_AfterFork()
+func runtime_AfterForkInChild()
// Implemented in clone_linux.c
func rawClone(flags _C_ulong, child_stack *byte, ptid *Pid_t, ctid *Pid_t, regs unsafe.Pointer) _C_long
@@ -62,16 +75,62 @@ func rawClone(flags _C_ulong, child_stack *byte, ptid *Pid_t, ctid *Pid_t, regs
// functions that do not grow the stack.
//go:norace
func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
+ // Set up and fork. This returns immediately in the parent or
+ // if there's an error.
+ r1, err1, p, locked := forkAndExecInChild1(argv0, argv, envv, chroot, dir, attr, sys, pipe)
+ if locked {
+ runtime_AfterFork()
+ }
+ if err1 != 0 {
+ return 0, err1
+ }
+
+ // parent; return PID
+ pid = int(r1)
+
+ if sys.UidMappings != nil || sys.GidMappings != nil {
+ Close(p[0])
+ err := writeUidGidMappings(pid, sys)
+ var err2 Errno
+ if err != nil {
+ err2 = err.(Errno)
+ }
+ RawSyscall(SYS_WRITE, uintptr(p[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
+ Close(p[1])
+ }
+
+ return pid, 0
+}
+
+// forkAndExecInChild1 implements the body of forkAndExecInChild up to
+// the parent's post-fork path. This is a separate function so we can
+// separate the child's and parent's stack frames if we're using
+// vfork.
+//
+// This is go:noinline because the point is to keep the stack frames
+// of this and forkAndExecInChild separate.
+//
+//go:noinline
+//go:norace
+func forkAndExecInChild1(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (r1 uintptr, err1 Errno, p [2]int, locked bool) {
+ // Defined in linux/prctl.h starting with Linux 4.3.
+ const (
+ PR_CAP_AMBIENT = 0x2f
+ PR_CAP_AMBIENT_RAISE = 0x2
+ )
+
+ // vfork requires that the child not touch any of the parent's
+ // active stack frames. Hence, the child does all post-fork
+ // processing in this stack frame and never returns, while the
+ // parent returns immediately from this frame and does all
+ // post-fork processing in the outer frame.
// Declare all variables at top in case any
// declarations require heap allocation (e.g., err1).
var (
- r1 uintptr
- r2 _C_long
- err1 Errno
err2 Errno
nextfd int
i int
- p [2]int
+ r2 int
)
// Record parent PID so child can test if it has died.
@@ -94,39 +153,42 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// synchronizing writing of User ID/Group ID mappings.
if sys.UidMappings != nil || sys.GidMappings != nil {
if err := forkExecPipe(p[:]); err != nil {
- return 0, err.(Errno)
+ err1 = err.(Errno)
+ return
}
}
// About to call fork.
// No more allocation or calls of non-assembly functions.
runtime_BeforeFork()
- r2 = rawClone(_C_ulong(uintptr(SIGCHLD)|sys.Cloneflags), nil, nil, nil, unsafe.Pointer(nil))
+ locked = true
+ r2 = int(rawClone(_C_ulong(uintptr(SIGCHLD)|sys.Cloneflags), nil, nil, nil, unsafe.Pointer(nil)))
if r2 < 0 {
- runtime_AfterFork()
- return 0, GetErrno()
+ err1 = GetErrno()
}
-
if r2 != 0 {
- // parent; return PID
- runtime_AfterFork()
- pid = int(r2)
-
- if sys.UidMappings != nil || sys.GidMappings != nil {
- Close(p[0])
- err := writeUidGidMappings(pid, sys)
- if err != nil {
- err2 = err.(Errno)
- }
- RawSyscall(SYS_WRITE, uintptr(p[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
- Close(p[1])
- }
-
- return pid, 0
+ // If we're in the parent, we must return immediately
+ // so we're not in the same stack frame as the child.
+ // This can at most use the return PC, which the child
+ // will not modify, and the results of
+ // rawVforkSyscall, which must have been written after
+ // the child was replaced.
+ r1 = uintptr(r2)
+ return
}
// Fork succeeded, now in child.
+ runtime_AfterForkInChild()
+
+ // Enable the "keep capabilities" flag to set ambient capabilities later.
+ if len(sys.AmbientCaps) > 0 {
+ _, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_KEEPCAPS, 1, 0, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
// Wait for User ID/Group ID mappings to be written.
if sys.UidMappings != nil || sys.GidMappings != nil {
if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(p[1]), 0, 0); err1 != 0 {
@@ -184,17 +246,30 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
}
- // Chroot
- if chroot != nil {
- err1 = raw_chroot(chroot)
+ // Unshare
+ if sys.Unshareflags != 0 {
+ err1 = rawUnshare(int(sys.Unshareflags))
if err1 != 0 {
goto childerror
}
+ // The unshare system call in Linux doesn't unshare mount points
+ // mounted with --shared. Systemd mounts / with --shared. For a
+ // long discussion of the pros and cons of this see debian bug 739593.
+ // The Go model of unsharing is more like Plan 9, where you ask
+ // to unshare and the namespaces are unconditionally unshared.
+ // To make this model work we must further mark / as MS_PRIVATE.
+ // This is what the standard unshare command does.
+ if sys.Unshareflags&CLONE_NEWNS == CLONE_NEWNS {
+ err1 = rawMount(&none[0], &slash[0], nil, MS_REC|MS_PRIVATE, nil)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
}
- // Unshare
- if sys.Unshareflags != 0 {
- _, _, err1 = RawSyscall(SYS_UNSHARE, sys.Unshareflags, 0, 0)
+ // Chroot
+ if chroot != nil {
+ err1 = raw_chroot(chroot)
if err1 != 0 {
goto childerror
}
@@ -207,10 +282,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
if ngroups > 0 {
groups = unsafe.Pointer(&cred.Groups[0])
}
- // Don't call setgroups in case of user namespace, gid mappings
- // and disabled setgroups, because otherwise unprivileged user namespace
- // will fail with any non-empty SysProcAttr.Credential.
- if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) {
+ if !(sys.GidMappings != nil && !sys.GidMappingsEnableSetgroups && ngroups == 0) && !cred.NoSetGroups {
err1 = raw_setgroups(ngroups, groups)
if err1 != 0 {
goto childerror
@@ -226,6 +298,13 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
}
+ for _, c := range sys.AmbientCaps {
+ _, _, err1 = RawSyscall6(SYS_PRCTL, PR_CAP_AMBIENT, uintptr(PR_CAP_AMBIENT_RAISE), c, 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
// Chdir
if dir != nil {
err1 = raw_chdir(dir)
@@ -321,7 +400,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// Set the controlling TTY to Ctty
if sys.Setctty {
- _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 0)
+ _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, sys.Ctty)
if err1 != 0 {
goto childerror
}
diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go
index 7a4b571..114deec 100644
--- a/libgo/go/syscall/exec_linux_test.go
+++ b/libgo/go/syscall/exec_linux_test.go
@@ -7,12 +7,20 @@
package syscall_test
import (
+ "flag"
+ "fmt"
+ "internal/testenv"
+ "io"
"io/ioutil"
"os"
"os/exec"
+ "os/user"
+ "path/filepath"
+ "strconv"
"strings"
"syscall"
"testing"
+ "unsafe"
)
// Check if we are in a chroot by checking if the inode of / is
@@ -49,6 +57,14 @@ func checkUserNS(t *testing.T) {
t.Skip("kernel prohibits user namespace in unprivileged process")
}
}
+ // On Centos 7 make sure they set the kernel parameter user_namespace=1
+ // See issue 16283 and 20796.
+ if _, err := os.Stat("/sys/module/user_namespace/parameters/enable"); err == nil {
+ buf, _ := ioutil.ReadFile("/sys/module/user_namespace/parameters/enabled")
+ if !strings.HasPrefix(string(buf), "Y") {
+ t.Skip("kernel doesn't support user namespaces")
+ }
+ }
// 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.
@@ -174,6 +190,12 @@ func TestUnshare(t *testing.T) {
}
out, err := cmd.CombinedOutput()
if err != nil {
+ if strings.Contains(err.Error(), "operation not permitted") {
+ // Issue 17206: despite all the checks above,
+ // this still reportedly fails for some users.
+ // (older kernels?). Just skip.
+ t.Skip("skipping due to permission error")
+ }
t.Fatalf("Cmd failed with err %v, output: %s", err, out)
}
@@ -205,9 +227,10 @@ func TestGroupCleanup(t *testing.T) {
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)"
+ expected := "uid=0(root) gid=0(root)"
// Just check prefix because some distros reportedly output a
// context parameter; see https://golang.org/issue/16224.
+ // Alpine does not output groups; see https://golang.org/issue/19938.
if !strings.HasPrefix(strOut, expected) {
t.Errorf("id command output: %q, expected prefix: %q", strOut, expected)
}
@@ -245,6 +268,7 @@ func TestGroupCleanupUserNamespace(t *testing.T) {
"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",
+ "uid=0(root) gid=0(root) groups=0(root),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody),65534(nobody)", // Alpine; see https://golang.org/issue/19938
}
for _, e := range expected {
if strOut == e {
@@ -253,3 +277,282 @@ func TestGroupCleanupUserNamespace(t *testing.T) {
}
t.Errorf("id command output: %q, expected one of %q", strOut, expected)
}
+
+// TestUnshareHelperProcess isn't a real test. It's used as a helper process
+// for TestUnshareMountNameSpace.
+func TestUnshareMountNameSpaceHelper(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+ if err := syscall.Mount("none", flag.Args()[0], "proc", 0, ""); err != nil {
+ fmt.Fprintf(os.Stderr, "unshare: mount %v failed: %v", os.Args, err)
+ os.Exit(2)
+ }
+}
+
+// Test for Issue 38471: unshare fails because systemd has forced / to be shared
+func TestUnshareMountNameSpace(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")
+ }
+
+ d, err := ioutil.TempDir("", "unshare")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+
+ cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
+
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ if strings.Contains(err.Error(), ": permission denied") {
+ t.Skipf("Skipping test (golang.org/issue/19698); unshare failed due to permissions: %s, %v", o, err)
+ }
+ t.Fatalf("unshare failed: %s, %v", o, err)
+ }
+
+ // How do we tell if the namespace was really unshared? It turns out
+ // to be simple: just try to remove the directory. If it's still mounted
+ // on the rm will fail with EBUSY. Then we have some cleanup to do:
+ // we must unmount it, then try to remove it again.
+
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir failed on %v: %v", d, err)
+ if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+ t.Errorf("Can't unmount %v: %v", d, err)
+ }
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir after unmount failed on %v: %v", d, err)
+ }
+ }
+}
+
+// Test for Issue 20103: unshare fails when chroot is used
+func TestUnshareMountNameSpaceChroot(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")
+ }
+
+ d, err := ioutil.TempDir("", "unshare")
+ if err != nil {
+ t.Fatalf("tempdir: %v", err)
+ }
+
+ // Since we are doing a chroot, we need the binary there,
+ // and it must be statically linked.
+ x := filepath.Join(d, "syscall.test")
+ cmd := exec.Command(testenv.GoToolPath(t), "test", "-c", "-o", x, "syscall")
+ cmd.Env = append(os.Environ(), "CGO_ENABLED=0")
+ if o, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("Build of syscall in chroot failed, output %v, err %v", o, err)
+ }
+
+ cmd = exec.Command("/syscall.test", "-test.run=TestUnshareMountNameSpaceHelper", "/")
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: d, Unshareflags: syscall.CLONE_NEWNS}
+
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ if strings.Contains(err.Error(), ": permission denied") {
+ t.Skipf("Skipping test (golang.org/issue/19698); unshare failed due to permissions: %s, %v", o, err)
+ }
+ t.Fatalf("unshare failed: %s, %v", o, err)
+ }
+
+ // How do we tell if the namespace was really unshared? It turns out
+ // to be simple: just try to remove the executable. If it's still mounted
+ // on, the rm will fail. Then we have some cleanup to do:
+ // we must force unmount it, then try to remove it again.
+
+ if err := os.Remove(x); err != nil {
+ t.Errorf("rm failed on %v: %v", x, err)
+ if err := syscall.Unmount(d, syscall.MNT_FORCE); err != nil {
+ t.Fatalf("Can't unmount %v: %v", d, err)
+ }
+ if err := os.Remove(x); err != nil {
+ t.Fatalf("rm failed on %v: %v", x, err)
+ }
+ }
+
+ if err := os.Remove(d); err != nil {
+ t.Errorf("rmdir failed on %v: %v", d, err)
+ }
+}
+
+type capHeader struct {
+ version uint32
+ pid int
+}
+
+type capData struct {
+ effective uint32
+ permitted uint32
+ inheritable uint32
+}
+
+const CAP_SYS_TIME = 25
+
+type caps struct {
+ hdr capHeader
+ data [2]capData
+}
+
+func getCaps() (caps, error) {
+ var c caps
+
+ // Get capability version
+ if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(nil)), 0); errno != 0 {
+ return c, fmt.Errorf("SYS_CAPGET: %v", errno)
+ }
+
+ // Get current capabilities
+ if _, _, errno := syscall.Syscall(syscall.SYS_CAPGET, uintptr(unsafe.Pointer(&c.hdr)), uintptr(unsafe.Pointer(&c.data[0])), 0); errno != 0 {
+ return c, fmt.Errorf("SYS_CAPGET: %v", errno)
+ }
+
+ return c, nil
+}
+
+func mustSupportAmbientCaps(t *testing.T) {
+ var uname syscall.Utsname
+ if err := syscall.Uname(&uname); err != nil {
+ t.Fatalf("Uname: %v", err)
+ }
+ var buf [65]byte
+ for i, b := range uname.Release {
+ buf[i] = byte(b)
+ }
+ ver := string(buf[:])
+ if i := strings.Index(ver, "\x00"); i != -1 {
+ ver = ver[:i]
+ }
+ if strings.HasPrefix(ver, "2.") ||
+ strings.HasPrefix(ver, "3.") ||
+ strings.HasPrefix(ver, "4.1.") ||
+ strings.HasPrefix(ver, "4.2.") {
+ t.Skipf("kernel version %q predates required 4.3; skipping test", ver)
+ }
+}
+
+// TestAmbientCapsHelper isn't a real test. It's used as a helper process for
+// TestAmbientCaps.
+func TestAmbientCapsHelper(*testing.T) {
+ if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
+ return
+ }
+ defer os.Exit(0)
+
+ caps, err := getCaps()
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ os.Exit(2)
+ }
+ if caps.data[0].effective&(1<<uint(CAP_SYS_TIME)) == 0 {
+ fmt.Fprintln(os.Stderr, "CAP_SYS_TIME unexpectedly not in the effective capability mask")
+ os.Exit(2)
+ }
+}
+
+func TestAmbientCaps(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")
+ }
+ mustSupportAmbientCaps(t)
+
+ // 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")
+ }
+
+ caps, err := getCaps()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Add CAP_SYS_TIME to the permitted and inheritable capability mask,
+ // otherwise we will not be able to add it to the ambient capability mask.
+ caps.data[0].permitted |= 1 << uint(CAP_SYS_TIME)
+ caps.data[0].inheritable |= 1 << uint(CAP_SYS_TIME)
+
+ if _, _, errno := syscall.Syscall(syscall.SYS_CAPSET, uintptr(unsafe.Pointer(&caps.hdr)), uintptr(unsafe.Pointer(&caps.data[0])), 0); errno != 0 {
+ t.Fatalf("SYS_CAPSET: %v", errno)
+ }
+
+ u, err := user.Lookup("nobody")
+ if err != nil {
+ t.Fatal(err)
+ }
+ uid, err := strconv.ParseInt(u.Uid, 0, 32)
+ if err != nil {
+ t.Fatal(err)
+ }
+ gid, err := strconv.ParseInt(u.Gid, 0, 32)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Copy the test binary to a temporary location which is readable by nobody.
+ f, err := ioutil.TempFile("", "gotest")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+ e, err := os.Open(os.Args[0])
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer e.Close()
+ if _, err := io.Copy(f, e); err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Chmod(0755); err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd := exec.Command(f.Name(), "-test.run=TestAmbientCapsHelper")
+ cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Credential: &syscall.Credential{
+ Uid: uint32(uid),
+ Gid: uint32(gid),
+ },
+ AmbientCaps: []uintptr{CAP_SYS_TIME},
+ }
+ if err := cmd.Run(); err != nil {
+ t.Fatal(err.Error())
+ }
+}
diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go
index f2bc741..8d83e91 100644
--- a/libgo/go/syscall/exec_unix.go
+++ b/libgo/go/syscall/exec_unix.go
@@ -163,9 +163,10 @@ func SetNonblock(fd int, nonblocking bool) (err error) {
// Credential holds user and group identities to be assumed
// by a child process started by StartProcess.
type Credential struct {
- Uid uint32 // User ID.
- Gid uint32 // Group ID.
- Groups []uint32 // Supplementary group IDs.
+ Uid uint32 // User ID.
+ Gid uint32 // Group ID.
+ Groups []uint32 // Supplementary group IDs.
+ NoSetGroups bool // If true, don't set supplementary groups
}
// ProcAttr holds attributes that will be applied to a new process started
@@ -292,6 +293,14 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
return pid, 0, err
}
+// Implemented in runtime package.
+func runtime_BeforeExec()
+func runtime_AfterExec()
+
+// execveSolaris is non-nil on Solaris, set to execve in exec_solaris.go; this
+// avoids a build dependency for other platforms.
+var execveSolaris func(path uintptr, argv uintptr, envp uintptr) (err Errno)
+
// Exec invokes the execve(2) system call.
func Exec(argv0 string, argv []string, envv []string) (err error) {
argv0p, err := BytePtrFromString(argv0)
@@ -306,6 +315,9 @@ func Exec(argv0 string, argv []string, envv []string) (err error) {
if err != nil {
return err
}
+ runtime_BeforeExec()
+
err1 := raw_execve(argv0p, &argvp[0], &envvp[0])
+ runtime_AfterExec()
return Errno(err1)
}
diff --git a/libgo/go/syscall/forkpipe_bsd.go b/libgo/go/syscall/forkpipe_bsd.go
new file mode 100644
index 0000000..d418072
--- /dev/null
+++ b/libgo/go/syscall/forkpipe_bsd.go
@@ -0,0 +1,20 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build darwin dragonfly netbsd openbsd
+
+package syscall
+
+func forkExecPipe(p []int) error {
+ err := Pipe(p)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(p[0], F_SETFD, FD_CLOEXEC)
+ if err != nil {
+ return err
+ }
+ _, err = fcntl(p[1], F_SETFD, FD_CLOEXEC)
+ return err
+}
diff --git a/libgo/go/syscall/net.go b/libgo/go/syscall/net.go
new file mode 100644
index 0000000..272d3af
--- /dev/null
+++ b/libgo/go/syscall/net.go
@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+// A RawConn is a raw network connection.
+type RawConn interface {
+ // Control invokes f on the underlying connection's file
+ // descriptor or handle.
+ // The file descriptor fd is guaranteed to remain valid while
+ // f executes but not after f returns.
+ Control(f func(fd uintptr)) error
+
+ // Read invokes f on the underlying connection's file
+ // descriptor or handle; f is expected to try to read from the
+ // file descriptor.
+ // If f returns true, Read returns. Otherwise Read blocks
+ // waiting for the connection to be ready for reading and
+ // tries again repeatedly.
+ // The file descriptor is guaranteed to remain valid while f
+ // executes but not after f returns.
+ Read(f func(fd uintptr) (done bool)) error
+
+ // Write is like Read but for writing.
+ Write(f func(fd uintptr) (done bool)) error
+}
+
+// Conn is implemented by some types in the net package to provide
+// access to the underlying file descriptor or handle.
+type Conn interface {
+ // SyscallConn returns a raw network connection.
+ SyscallConn() (RawConn, error)
+}
diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go
index 91dfa9a..8415383 100644
--- a/libgo/go/syscall/syscall.go
+++ b/libgo/go/syscall/syscall.go
@@ -22,7 +22,10 @@
// Go repository should be migrated to use the corresponding
// package in the golang.org/x/sys repository. That is also where updates
// required by new systems or versions should be applied.
-// See https://golang.org/s/go1.4-syscall for more information.
+// Signal, Errno and SysProcAttr are not yet available in
+// golang.org/x/sys and must still be referenced from the
+// syscall package. See https://golang.org/s/go1.4-syscall
+// for more information.
//
package syscall
@@ -102,11 +105,3 @@ func (tv *Timeval) Nano() int64 {
// Getpagesize is provided by the runtime.
func Getpagesize() int
-
-// use is a no-op, but the compiler cannot see that it is.
-// Calling use(p) ensures that p is kept live until that point.
-// This was needed until Go 1.6 to call syscall.Syscall correctly.
-// As of Go 1.6 the compiler handles that case automatically.
-// The uses and definition of use can be removed early in the Go 1.7 cycle.
-//go:noescape
-func use(p unsafe.Pointer)
diff --git a/libgo/go/syscall/syscall_dragonfly.go b/libgo/go/syscall/syscall_dragonfly.go
index c2fc67f..3e6617c 100644
--- a/libgo/go/syscall/syscall_dragonfly.go
+++ b/libgo/go/syscall/syscall_dragonfly.go
@@ -1,4 +1,4 @@
-// Copyright 2009,2010 The Go Authors. All rights reserved.
+// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
@@ -15,7 +15,7 @@ func direntReclen(buf []byte) (uint64, bool) {
if !ok {
return 0, false
}
- return (16 + namlen + 1 + 7) & ^uint64(7), true
+ return (16 + namlen + 1 + 7) &^ 7, true
}
func direntNamlen(buf []byte) (uint64, bool) {
diff --git a/libgo/go/syscall/syscall_linux_386.go b/libgo/go/syscall/syscall_linux_386.go
index 591d3e1..9abcab9 100644
--- a/libgo/go/syscall/syscall_linux_386.go
+++ b/libgo/go/syscall/syscall_linux_386.go
@@ -22,3 +22,7 @@ func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
}
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+ panic("not implemented")
+}
diff --git a/libgo/go/syscall/syscall_linux_amd64.go b/libgo/go/syscall/syscall_linux_amd64.go
index 609faed06..8ee7cd7 100644
--- a/libgo/go/syscall/syscall_linux_amd64.go
+++ b/libgo/go/syscall/syscall_linux_amd64.go
@@ -23,3 +23,5 @@ func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
}
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno)
diff --git a/libgo/go/syscall/syscall_linux_mipsx.go b/libgo/go/syscall/syscall_linux_mipsx.go
index 06dd1ea..1a15218 100644
--- a/libgo/go/syscall/syscall_linux_mipsx.go
+++ b/libgo/go/syscall/syscall_linux_mipsx.go
@@ -24,3 +24,7 @@ func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
return ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))
}
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+ panic("not implemented")
+}
diff --git a/libgo/go/syscall/syscall_linux_s390x.go b/libgo/go/syscall/syscall_linux_s390x.go
index 1767a6e..fa3bb30 100644
--- a/libgo/go/syscall/syscall_linux_s390x.go
+++ b/libgo/go/syscall/syscall_linux_s390x.go
@@ -46,3 +46,7 @@ func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
}
return ptrace(PTRACE_POKEUSR_AREA, pid, uintptr(unsafe.Pointer(&parea)), 0)
}
+
+func rawVforkSyscall(trap, a1 uintptr) (r1 uintptr, err Errno) {
+ panic("not implemented")
+}
diff --git a/libgo/go/syscall/syscall_unix_test.go b/libgo/go/syscall/syscall_unix_test.go
index 2f25d18..b1fe78d 100644
--- a/libgo/go/syscall/syscall_unix_test.go
+++ b/libgo/go/syscall/syscall_unix_test.go
@@ -78,12 +78,16 @@ func TestFcntlFlock(t *testing.T) {
}
if os.Getenv("GO_WANT_HELPER_PROCESS") == "" {
// parent
- name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+ tempDir, err := ioutil.TempDir("", "TestFcntlFlock")
+ if err != nil {
+ t.Fatalf("Failed to create temp dir: %v", err)
+ }
+ name := filepath.Join(tempDir, "TestFcntlFlock")
fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
if err != nil {
t.Fatalf("Open failed: %v", err)
}
- defer syscall.Unlink(name)
+ defer os.RemoveAll(tempDir)
defer syscall.Close(fd)
if err := syscall.Ftruncate(fd, 1<<20); err != nil {
t.Fatalf("Ftruncate(1<<20) failed: %v", err)