diff options
Diffstat (limited to 'libgo/go/syscall')
-rw-r--r-- | libgo/go/syscall/env_plan9.go | 86 | ||||
-rw-r--r-- | libgo/go/syscall/env_unix.go | 60 | ||||
-rw-r--r-- | libgo/go/syscall/env_windows.go | 8 | ||||
-rw-r--r-- | libgo/go/syscall/exec_linux.go | 123 | ||||
-rw-r--r-- | libgo/go/syscall/exec_windows.go | 15 | ||||
-rw-r--r-- | libgo/go/syscall/export_test.go | 7 | ||||
-rw-r--r-- | libgo/go/syscall/netlink_linux.go | 3 | ||||
-rw-r--r-- | libgo/go/syscall/route_bsd.go | 2 | ||||
-rw-r--r-- | libgo/go/syscall/str.go | 6 | ||||
-rw-r--r-- | libgo/go/syscall/syscall.go | 12 | ||||
-rw-r--r-- | libgo/go/syscall/syscall_errno.go | 2 | ||||
-rw-r--r-- | libgo/go/syscall/syscall_test.go | 17 | ||||
-rw-r--r-- | libgo/go/syscall/syscall_unix.go | 2 |
13 files changed, 244 insertions, 99 deletions
diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go index 9587ab5af9d..9ea36c886ab 100644 --- a/libgo/go/syscall/env_plan9.go +++ b/libgo/go/syscall/env_plan9.go @@ -8,22 +8,9 @@ package syscall import ( "errors" - "sync" ) var ( - // envOnce guards copyenv, which populates env. - envOnce sync.Once - - // envLock guards env and envs. - envLock sync.RWMutex - - // env maps from an environment variable to its value. - env = make(map[string]string) - - // envs contains elements of env in the form "key=value". - envs []string - errZeroLengthKey = errors.New("zero length key") errShortWrite = errors.New("i/o count too small") ) @@ -64,46 +51,14 @@ func writeenv(key, value string) error { return nil } -func copyenv() { - fd, err := Open("/env", O_RDONLY) - if err != nil { - return - } - defer Close(fd) - files, err := readdirnames(fd) - if err != nil { - return - } - envs = make([]string, len(files)) - i := 0 - for _, key := range files { - v, err := readenv(key) - if err != nil { - continue - } - env[key] = v - envs[i] = key + "=" + v - i++ - } -} - func Getenv(key string) (value string, found bool) { if len(key) == 0 { return "", false } - - envLock.RLock() - defer envLock.RUnlock() - - if v, ok := env[key]; ok { - return v, true - } v, err := readenv(key) if err != nil { return "", false } - env[key] = v - envs = append(envs, key+"="+v) return v, true } @@ -111,32 +66,43 @@ func Setenv(key, value string) error { if len(key) == 0 { return errZeroLengthKey } - - envLock.Lock() - defer envLock.Unlock() - err := writeenv(key, value) if err != nil { return err } - env[key] = value - envs = append(envs, key+"="+value) return nil } func Clearenv() { - envLock.Lock() - defer envLock.Unlock() - - env = make(map[string]string) - envs = []string{} RawSyscall(SYS_RFORK, RFCENVG, 0, 0) } +func Unsetenv(key string) error { + if len(key) == 0 { + return errZeroLengthKey + } + Remove("/env/" + key) + return nil +} + func Environ() []string { - envLock.RLock() - defer envLock.RUnlock() + fd, err := Open("/env", O_RDONLY) + if err != nil { + return nil + } + defer Close(fd) + files, err := readdirnames(fd) + if err != nil { + return nil + } + ret := make([]string, 0, len(files)) - envOnce.Do(copyenv) - return append([]string(nil), envs...) + for _, key := range files { + v, err := readenv(key) + if err != nil { + continue + } + ret = append(ret, key+"="+v) + } + return ret } diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go index 7f39958437c..b5ded9c763c 100644 --- a/libgo/go/syscall/env_unix.go +++ b/libgo/go/syscall/env_unix.go @@ -20,23 +20,33 @@ var ( // env maps from an environment variable to its first occurrence in envs. env map[string]int - // envs is provided by the runtime. elements are expected to be - // of the form "key=value". - Envs []string + // envs is provided by the runtime. elements are expected to + // be of the form "key=value". An empty string means deleted + // (or a duplicate to be ignored). + envs []string = runtime_envs() ) -// setenv_c is provided by the runtime, but is a no-op if cgo isn't -// loaded. +func runtime_envs() []string // in package runtime + +// setenv_c and unsetenv_c are provided by the runtime but are no-ops +// if cgo isn't loaded. func setenv_c(k, v string) +func unsetenv_c(k string) func copyenv() { env = make(map[string]int) - for i, s := range Envs { + for i, s := range envs { for j := 0; j < len(s); j++ { if s[j] == '=' { key := s[:j] if _, ok := env[key]; !ok { - env[key] = i + env[key] = i // first mention of key + } else { + // Clear duplicate keys. This permits Unsetenv to + // safely delete only the first item without + // worrying about unshadowing a later one, + // which might be a security problem. + envs[i] = "" } break } @@ -44,6 +54,20 @@ func copyenv() { } } +func Unsetenv(key string) error { + envOnce.Do(copyenv) + + envLock.Lock() + defer envLock.Unlock() + + if i, ok := env[key]; ok { + envs[i] = "" + delete(env, key) + } + unsetenv_c(key) + return nil +} + func Getenv(key string) (value string, found bool) { envOnce.Do(copyenv) if len(key) == 0 { @@ -57,7 +81,7 @@ func Getenv(key string) (value string, found bool) { if !ok { return "", false } - s := Envs[i] + s := envs[i] for i := 0; i < len(s); i++ { if s[i] == '=' { return s[i+1:], true @@ -88,10 +112,10 @@ func Setenv(key, value string) error { i, ok := env[key] kv := key + "=" + value if ok { - Envs[i] = kv + envs[i] = kv } else { - i = len(Envs) - Envs = append(Envs, kv) + i = len(envs) + envs = append(envs, kv) } env[key] = i setenv_c(key, value) @@ -104,16 +128,22 @@ func Clearenv() { envLock.Lock() defer envLock.Unlock() + for k := range env { + unsetenv_c(k) + } env = make(map[string]int) - Envs = []string{} - // TODO(bradfitz): pass through to C + envs = []string{} } func Environ() []string { envOnce.Do(copyenv) envLock.RLock() defer envLock.RUnlock() - a := make([]string, len(Envs)) - copy(a, Envs) + a := make([]string, 0, len(envs)) + for _, env := range envs { + if env != "" { + a = append(a, env) + } + } return a } diff --git a/libgo/go/syscall/env_windows.go b/libgo/go/syscall/env_windows.go index 420b3872464..bc21690d9fd 100644 --- a/libgo/go/syscall/env_windows.go +++ b/libgo/go/syscall/env_windows.go @@ -47,6 +47,14 @@ func Setenv(key, value string) error { return nil } +func Unsetenv(key string) error { + keyp, err := UTF16PtrFromString(key) + if err != nil { + return err + } + return SetEnvironmentVariable(keyp, nil) +} + func Clearenv() { for _, s := range Environ() { // Environment variables can begin with = diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go index 2371902cbaa..97bde0c4f52 100644 --- a/libgo/go/syscall/exec_linux.go +++ b/libgo/go/syscall/exec_linux.go @@ -14,17 +14,27 @@ 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 +// SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux. +// See user_namespaces(7). +type SysProcIDMap struct { + ContainerID int // Container ID. + HostID int // Host ID. + Size int // Size. +} + type SysProcAttr struct { - Chroot string // Chroot. - Credential *Credential // Credential. - Ptrace bool // Enable tracing. - Setsid bool // Create session. - Setpgid bool // Set process group ID to new pid (SYSV setpgrp) - Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) - Noctty bool // Detach fd 0 from controlling terminal - Ctty int // Controlling TTY fd (Linux only) - Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) - Cloneflags uintptr // Flags for clone calls (Linux only) + Chroot string // Chroot. + Credential *Credential // Credential. + Ptrace bool // Enable tracing. + Setsid bool // Create session. + Setpgid bool // Set process group ID to new pid (SYSV setpgrp) + Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) + Noctty bool // Detach fd 0 from controlling terminal + Ctty int // Controlling TTY fd (Linux only) + Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) + Cloneflags uintptr // Flags for clone calls (Linux only) + UidMappings []SysProcIDMap // User ID mappings for user namespaces. + GidMappings []SysProcIDMap // Group ID mappings for user namespaces. } // Implemented in runtime package. @@ -46,8 +56,10 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr var ( r1 uintptr err1 Errno + err2 Errno nextfd int i int + p [2]int ) // Guard against side effects of shuffling fds below. @@ -63,6 +75,14 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } nextfd++ + // Allocate another pipe for parent to child communication for + // 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) + } + } + // About to call fork. // No more allocation or calls of non-assembly functions. runtime_BeforeFork() @@ -79,11 +99,42 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr if r1 != 0 { // parent; return PID runtime_AfterFork() - return int(r1), 0 + pid = int(r1) + + 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 } // Fork succeeded, now in child. + // 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 { + goto childerror + } + r1, _, err1 = RawSyscall(SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2)) + if err1 != 0 { + goto childerror + } + if r1 != unsafe.Sizeof(err2) { + err1 = EINVAL + goto childerror + } + if err2 != 0 { + err1 = err2 + goto childerror + } + } + // Parent death signal if sys.Pdeathsig != 0 { _, err1 = raw_prctl(PR_SET_PDEATHSIG, int(sys.Pdeathsig), 0, 0, 0) @@ -282,3 +333,53 @@ func forkExecPipe(p []int) (err error) { } return } + +// writeIDMappings writes the user namespace User ID or Group ID mappings to the specified path. +func writeIDMappings(path string, idMap []SysProcIDMap) error { + fd, err := Open(path, O_RDWR, 0) + if err != nil { + return err + } + + data := "" + for _, im := range idMap { + data = data + itoa(im.ContainerID) + " " + itoa(im.HostID) + " " + itoa(im.Size) + "\n" + } + + bytes, err := ByteSliceFromString(data) + if err != nil { + Close(fd) + return err + } + + if _, err := Write(fd, bytes); err != nil { + Close(fd) + return err + } + + if err := Close(fd); err != nil { + return err + } + + return nil +} + +// writeUidGidMappings writes User ID and Group ID mappings for user namespaces +// for a process and it is called from the parent process. +func writeUidGidMappings(pid int, sys *SysProcAttr) error { + if sys.UidMappings != nil { + uidf := "/proc/" + itoa(pid) + "/uid_map" + if err := writeIDMappings(uidf, sys.UidMappings); err != nil { + return err + } + } + + if sys.GidMappings != nil { + gidf := "/proc/" + itoa(pid) + "/gid_map" + if err := writeIDMappings(gidf, sys.GidMappings); err != nil { + return err + } + } + + return nil +} diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go index 82abc0715e5..936aeb577bc 100644 --- a/libgo/go/syscall/exec_windows.go +++ b/libgo/go/syscall/exec_windows.go @@ -129,9 +129,8 @@ func SetNonblock(fd Handle, nonblocking bool) (err error) { return nil } -// getFullPath retrieves the full path of the specified file. -// Just a wrapper for Windows GetFullPathName api. -func getFullPath(name string) (path string, err error) { +// FullPath retrieves the full path of the specified file. +func FullPath(name string) (path string, err error) { p, err := UTF16PtrFromString(name) if err != nil { return "", err @@ -160,7 +159,7 @@ func isSlash(c uint8) bool { } func normalizeDir(dir string) (name string, err error) { - ndir, err := getFullPath(dir) + ndir, err := FullPath(dir) if err != nil { return "", err } @@ -199,9 +198,9 @@ func joinExeDirAndFName(dir, p string) (name string, err error) { return "", err } if volToUpper(int(p[0])) == volToUpper(int(d[0])) { - return getFullPath(d + "\\" + p[2:]) + return FullPath(d + "\\" + p[2:]) } else { - return getFullPath(p) + return FullPath(p) } } } else { @@ -211,9 +210,9 @@ func joinExeDirAndFName(dir, p string) (name string, err error) { return "", err } if isSlash(p[0]) { - return getFullPath(d[:2] + p) + return FullPath(d[:2] + p) } else { - return getFullPath(d + "\\" + p) + return FullPath(d + "\\" + p) } } // we shouldn't be here diff --git a/libgo/go/syscall/export_test.go b/libgo/go/syscall/export_test.go new file mode 100644 index 00000000000..c9774622c87 --- /dev/null +++ b/libgo/go/syscall/export_test.go @@ -0,0 +1,7 @@ +// Copyright 2014 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 + +var Itoa = itoa diff --git a/libgo/go/syscall/netlink_linux.go b/libgo/go/syscall/netlink_linux.go index 49550ea2f02..1b73dce8274 100644 --- a/libgo/go/syscall/netlink_linux.go +++ b/libgo/go/syscall/netlink_linux.go @@ -64,9 +64,10 @@ func NetlinkRIB(proto, family int) ([]byte, error) { return nil, err } var tab []byte + rbNew := make([]byte, Getpagesize()) done: for { - rb := make([]byte, Getpagesize()) + rb := rbNew nr, _, err := Recvfrom(s, rb, 0) if err != nil { return nil, err diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go index 48af587450b..1dabe42531b 100644 --- a/libgo/go/syscall/route_bsd.go +++ b/libgo/go/syscall/route_bsd.go @@ -153,7 +153,7 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) { // RTAX_NETMASK socket address on the FreeBSD kernel. preferredFamily := uint8(AF_UNSPEC) for i := uint(0); i < RTAX_MAX; i++ { - if m.Header.Addrs&rtaIfaMask&(1<<i) == 0 { + if m.Header.Addrs&(1<<i) == 0 { continue } rsa := (*RawSockaddr)(unsafe.Pointer(&b[0])) diff --git a/libgo/go/syscall/str.go b/libgo/go/syscall/str.go index 0fce842e8c1..2ddf04b2275 100644 --- a/libgo/go/syscall/str.go +++ b/libgo/go/syscall/str.go @@ -6,8 +6,12 @@ package syscall func itoa(val int) string { // do it here rather than with fmt to avoid dependency if val < 0 { - return "-" + itoa(-val) + return "-" + uitoa(uint(-val)) } + return uitoa(uint(val)) +} + +func uitoa(val uint) string { var buf [32]byte // big enough for int64 i := len(buf) - 1 for val >= 10 { diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go index c4f2125140e..ef9d7d65973 100644 --- a/libgo/go/syscall/syscall.go +++ b/libgo/go/syscall/syscall.go @@ -17,6 +17,13 @@ // These calls return err == nil to indicate success; otherwise // err is an operating system error describing the failure. // On most systems, that error has type syscall.Errno. +// +// NOTE: This package is locked down. Code outside the standard +// Go repository should be migrated to use the corresponding +// package in the go.sys subrepository. 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. +// package syscall import "unsafe" @@ -85,3 +92,8 @@ func (ts *Timespec) Nano() int64 { func (tv *Timeval) Nano() int64 { return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000 } + +// 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. +//go:noescape +func use(p unsafe.Pointer) diff --git a/libgo/go/syscall/syscall_errno.go b/libgo/go/syscall/syscall_errno.go index 810572f58a9..01618d173a1 100644 --- a/libgo/go/syscall/syscall_errno.go +++ b/libgo/go/syscall/syscall_errno.go @@ -18,7 +18,7 @@ func (e Errno) Error() string { } func (e Errno) Temporary() bool { - return e == EINTR || e == EMFILE || e.Timeout() + return e == EINTR || e == EMFILE || e == ECONNRESET || e == ECONNABORTED || e.Timeout() } func (e Errno) Timeout() bool { diff --git a/libgo/go/syscall/syscall_test.go b/libgo/go/syscall/syscall_test.go index 2a39b54f1b2..846c4873d28 100644 --- a/libgo/go/syscall/syscall_test.go +++ b/libgo/go/syscall/syscall_test.go @@ -5,6 +5,7 @@ package syscall_test import ( + "fmt" "syscall" "testing" ) @@ -28,3 +29,19 @@ func TestEnv(t *testing.T) { // make sure TESTENV gets set to "", not deleted testSetGetenv(t, "TESTENV", "") } + +func TestItoa(t *testing.T) { + // Make most negative integer: 0x8000... + i := 1 + for i<<1 != 0 { + i <<= 1 + } + if i >= 0 { + t.Fatal("bad math") + } + s := syscall.Itoa(i) + f := fmt.Sprint(i) + if s != f { + t.Fatalf("itoa(%d) = %s, want %s", i, s, f) + } +} diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go index a64b05fb5cc..74f10c29da5 100644 --- a/libgo/go/syscall/syscall_unix.go +++ b/libgo/go/syscall/syscall_unix.go @@ -125,7 +125,7 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d cap int }{addr, length, length} - // Use unsafeto turn sl into a []byte. + // Use unsafe to turn sl into a []byte. b := *(*[]byte)(unsafe.Pointer(&sl)) // Register mapping in m and return it. |