2011-04-02 15:24:03 -06:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
// Fork, exec, wait, etc.
|
|
|
|
|
|
|
|
package syscall
|
|
|
|
|
|
|
|
import (
|
syscall, os: fix a fork-exec/wait race in Plan 9.
On Plan 9, only the parent of a given process can enter its wait
queue. When a Go program tries to fork-exec a child process
and subsequently waits for it to finish, the goroutines doing
these two tasks do not necessarily tie themselves to the same
(or any single) OS thread. In the case that the fork and the wait
system calls happen on different OS threads (say, due to a
goroutine being rescheduled somewhere along the way), the
wait() will either return an error or end up waiting for a
completely different child than was intended.
This change forces the fork and wait syscalls to happen in the
same goroutine and ties that goroutine to its OS thread until
the child exits. The PID of the child is recorded upon fork and
exit, and de-queued once the child's wait message has been read.
The Wait API, then, is translated into a synthetic implementation
that simply waits for the requested PID to show up in the queue
and then reads the associated stats.
R=rsc, rminnich, npe, mirtchovski, ality
CC=golang-dev
https://golang.org/cl/6545051
2013-01-18 14:43:25 -07:00
|
|
|
"runtime"
|
2011-04-02 15:24:03 -06:00
|
|
|
"sync"
|
|
|
|
"unsafe"
|
|
|
|
)
|
|
|
|
|
2016-05-06 07:21:52 -06:00
|
|
|
// ForkLock is not used on plan9.
|
2011-04-02 15:24:03 -06:00
|
|
|
var ForkLock sync.RWMutex
|
|
|
|
|
2016-04-29 10:39:33 -06:00
|
|
|
// gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order.
|
|
|
|
// It returns the string as a byte slice, or nil if b is too short to contain the length or
|
|
|
|
// the full string.
|
|
|
|
//go:nosplit
|
|
|
|
func gstringb(b []byte) []byte {
|
|
|
|
if len(b) < 2 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
n, b := gbit16(b)
|
|
|
|
if int(n) > len(b) {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return b[:n]
|
|
|
|
}
|
|
|
|
|
|
|
|
// Offset of the name field in a 9P directory entry - see UnmarshalDir() in dir_plan9.go
|
|
|
|
const nameOffset = 39
|
|
|
|
|
|
|
|
// gdirname returns the first filename from a buffer of directory entries,
|
|
|
|
// and a slice containing the remaining directory entries.
|
|
|
|
// If the buffer doesn't start with a valid directory entry, the returned name is nil.
|
|
|
|
//go:nosplit
|
|
|
|
func gdirname(buf []byte) (name []byte, rest []byte) {
|
|
|
|
if len(buf) < 2 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
size, buf := gbit16(buf)
|
|
|
|
if size < STATFIXLEN || int(size) > len(buf) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
name = gstringb(buf[nameOffset:size])
|
|
|
|
rest = buf[size:]
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-05-18 13:50:00 -06:00
|
|
|
// StringSlicePtr converts a slice of strings to a slice of pointers
|
|
|
|
// to NUL-terminated byte arrays. If any string contains a NUL byte
|
|
|
|
// this function panics instead of returning an error.
|
|
|
|
//
|
|
|
|
// Deprecated: Use SlicePtrFromStrings instead.
|
2011-06-10 17:25:18 -06:00
|
|
|
func StringSlicePtr(ss []string) []*byte {
|
2011-04-02 15:24:03 -06:00
|
|
|
bb := make([]*byte, len(ss)+1)
|
|
|
|
for i := 0; i < len(ss); i++ {
|
|
|
|
bb[i] = StringBytePtr(ss[i])
|
|
|
|
}
|
|
|
|
bb[len(ss)] = nil
|
|
|
|
return bb
|
|
|
|
}
|
|
|
|
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
// SlicePtrFromStrings converts a slice of strings to a slice of
|
2015-05-18 13:50:00 -06:00
|
|
|
// pointers to NUL-terminated byte arrays. If any string contains
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
// a NUL byte, it returns (nil, EINVAL).
|
|
|
|
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
|
|
|
|
var err error
|
|
|
|
bb := make([]*byte, len(ss)+1)
|
|
|
|
for i := 0; i < len(ss); i++ {
|
|
|
|
bb[i], err = BytePtrFromString(ss[i])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
bb[len(ss)] = nil
|
|
|
|
return bb, nil
|
|
|
|
}
|
|
|
|
|
2011-04-02 15:24:03 -06:00
|
|
|
// readdirnames returns the names of files inside the directory represented by dirfd.
|
2011-11-16 15:37:54 -07:00
|
|
|
func readdirnames(dirfd int) (names []string, err error) {
|
2012-04-26 03:59:13 -06:00
|
|
|
names = make([]string, 0, 100)
|
2011-04-02 15:24:03 -06:00
|
|
|
var buf [STATMAX]byte
|
|
|
|
|
|
|
|
for {
|
|
|
|
n, e := Read(dirfd, buf[:])
|
|
|
|
if e != nil {
|
2012-04-26 03:59:13 -06:00
|
|
|
return nil, e
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
if n == 0 {
|
|
|
|
break
|
|
|
|
}
|
2016-04-29 10:39:33 -06:00
|
|
|
for b := buf[:n]; len(b) > 0; {
|
|
|
|
var s []byte
|
|
|
|
s, b = gdirname(b)
|
|
|
|
if s == nil {
|
2012-11-26 16:26:46 -07:00
|
|
|
return nil, ErrBadStat
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
2016-04-29 10:39:33 -06:00
|
|
|
names = append(names, string(s))
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
}
|
2012-04-26 03:59:13 -06:00
|
|
|
return
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
2016-04-29 10:39:33 -06:00
|
|
|
// name of the directory containing names and control files for all open file descriptors
|
|
|
|
var dupdev, _ = BytePtrFromString("#d")
|
2011-04-02 15:24:03 -06:00
|
|
|
|
|
|
|
// forkAndExecInChild forks the process, calling dup onto 0..len(fd)
|
|
|
|
// and finally invoking exec(argv0, argvv, envv) in the child.
|
|
|
|
// If a dup or exec fails, it writes the error string to pipe.
|
|
|
|
// (The pipe write end is close-on-exec so if exec succeeds, it will be closed.)
|
|
|
|
//
|
|
|
|
// In the child, this function must not acquire any locks, because
|
2016-03-01 16:21:55 -07:00
|
|
|
// they might have been locked at the time of the fork. This means
|
2011-04-02 15:24:03 -06:00
|
|
|
// no rescheduling, no malloc calls, and no new stack segments.
|
|
|
|
// The calls to RawSyscall are okay because they are assembly
|
|
|
|
// functions that do not grow the stack.
|
2015-10-19 18:01:37 -06:00
|
|
|
//go:norace
|
2016-04-29 10:39:33 -06:00
|
|
|
func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, pipe int, rflag int) (pid int, err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
// Declare all variables at top in case any
|
|
|
|
// declarations require heap allocation (e.g., errbuf).
|
|
|
|
var (
|
|
|
|
r1 uintptr
|
|
|
|
nextfd int
|
|
|
|
i int
|
|
|
|
clearenv int
|
|
|
|
envfd int
|
|
|
|
errbuf [ERRMAX]byte
|
2016-04-29 10:39:33 -06:00
|
|
|
statbuf [STATMAX]byte
|
|
|
|
dupdevfd int
|
2011-04-02 15:24:03 -06:00
|
|
|
)
|
|
|
|
|
2013-04-30 12:52:15 -06:00
|
|
|
// Guard against side effects of shuffling fds below.
|
|
|
|
// Make sure that nextfd is beyond any currently open files so
|
|
|
|
// that we can't run the risk of overwriting any of them.
|
2012-02-16 12:04:51 -07:00
|
|
|
fd := make([]int, len(attr.Files))
|
2013-04-30 12:52:15 -06:00
|
|
|
nextfd = len(attr.Files)
|
2012-02-16 12:04:51 -07:00
|
|
|
for i, ufd := range attr.Files {
|
2013-04-30 12:52:15 -06:00
|
|
|
if nextfd < int(ufd) {
|
|
|
|
nextfd = int(ufd)
|
|
|
|
}
|
2012-02-16 12:04:51 -07:00
|
|
|
fd[i] = int(ufd)
|
|
|
|
}
|
2013-04-30 12:52:15 -06:00
|
|
|
nextfd++
|
2011-04-02 15:24:03 -06:00
|
|
|
|
|
|
|
if envv != nil {
|
|
|
|
clearenv = RFCENVG
|
|
|
|
}
|
|
|
|
|
|
|
|
// About to call fork.
|
|
|
|
// No more allocation or calls of non-assembly functions.
|
2011-06-14 08:49:34 -06:00
|
|
|
r1, _, _ = RawSyscall(SYS_RFORK, uintptr(RFPROC|RFFDG|RFREND|clearenv|rflag), 0, 0)
|
2011-04-02 15:24:03 -06:00
|
|
|
|
|
|
|
if r1 != 0 {
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 {
|
2011-04-02 15:24:03 -06:00
|
|
|
return 0, NewError(errstr())
|
|
|
|
}
|
|
|
|
// parent; return PID
|
|
|
|
return int(r1), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fork succeeded, now in child.
|
|
|
|
|
|
|
|
// Close fds we don't need.
|
2016-04-29 10:39:33 -06:00
|
|
|
r1, _, _ = RawSyscall(SYS_OPEN, uintptr(unsafe.Pointer(dupdev)), uintptr(O_RDONLY), 0)
|
|
|
|
dupdevfd = int(r1)
|
|
|
|
if dupdevfd == -1 {
|
|
|
|
goto childerror
|
|
|
|
}
|
|
|
|
dirloop:
|
|
|
|
for {
|
|
|
|
r1, _, _ = RawSyscall6(SYS_PREAD, uintptr(dupdevfd), uintptr(unsafe.Pointer(&statbuf[0])), uintptr(len(statbuf)), ^uintptr(0), ^uintptr(0), 0)
|
|
|
|
n := int(r1)
|
|
|
|
switch n {
|
|
|
|
case -1:
|
|
|
|
goto childerror
|
|
|
|
case 0:
|
|
|
|
break dirloop
|
|
|
|
}
|
|
|
|
for b := statbuf[:n]; len(b) > 0; {
|
|
|
|
var s []byte
|
|
|
|
s, b = gdirname(b)
|
|
|
|
if s == nil {
|
|
|
|
copy(errbuf[:], ErrBadStat.Error())
|
|
|
|
goto childerror1
|
|
|
|
}
|
|
|
|
if s[len(s)-1] == 'l' {
|
|
|
|
// control file for descriptor <N> is named <N>ctl
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
closeFdExcept(int(atoi(s)), pipe, dupdevfd, fd)
|
2016-03-17 04:20:54 -06:00
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
2016-04-29 10:39:33 -06:00
|
|
|
RawSyscall(SYS_CLOSE, uintptr(dupdevfd), 0, 0)
|
2011-04-02 15:24:03 -06:00
|
|
|
|
2016-04-29 10:39:33 -06:00
|
|
|
// Write new environment variables.
|
2011-04-02 15:24:03 -06:00
|
|
|
if envv != nil {
|
|
|
|
for i = 0; i < len(envv); i++ {
|
|
|
|
r1, _, _ = RawSyscall(SYS_CREATE, uintptr(unsafe.Pointer(envv[i].name)), uintptr(O_WRONLY), uintptr(0666))
|
|
|
|
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 {
|
2011-04-02 15:24:03 -06:00
|
|
|
goto childerror
|
|
|
|
}
|
|
|
|
|
|
|
|
envfd = int(r1)
|
|
|
|
|
|
|
|
r1, _, _ = RawSyscall6(SYS_PWRITE, uintptr(envfd), uintptr(unsafe.Pointer(envv[i].value)), uintptr(envv[i].nvalue),
|
|
|
|
^uintptr(0), ^uintptr(0), 0)
|
|
|
|
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 || int(r1) != envv[i].nvalue {
|
2011-04-02 15:24:03 -06:00
|
|
|
goto childerror
|
|
|
|
}
|
|
|
|
|
|
|
|
r1, _, _ = RawSyscall(SYS_CLOSE, uintptr(envfd), 0, 0)
|
|
|
|
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 {
|
2011-04-02 15:24:03 -06:00
|
|
|
goto childerror
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Chdir
|
|
|
|
if dir != nil {
|
|
|
|
r1, _, _ = RawSyscall(SYS_CHDIR, uintptr(unsafe.Pointer(dir)), 0, 0)
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 {
|
2011-04-02 15:24:03 -06:00
|
|
|
goto childerror
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pass 1: look for fd[i] < i and move those up above len(fd)
|
|
|
|
// so that pass 2 won't stomp on an fd it needs later.
|
|
|
|
if pipe < nextfd {
|
|
|
|
r1, _, _ = RawSyscall(SYS_DUP, uintptr(pipe), uintptr(nextfd), 0)
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 {
|
2011-04-02 15:24:03 -06:00
|
|
|
goto childerror
|
|
|
|
}
|
|
|
|
pipe = nextfd
|
|
|
|
nextfd++
|
|
|
|
}
|
|
|
|
for i = 0; i < len(fd); i++ {
|
|
|
|
if fd[i] >= 0 && fd[i] < int(i) {
|
2016-03-26 13:35:21 -06:00
|
|
|
if nextfd == pipe { // don't stomp on pipe
|
|
|
|
nextfd++
|
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(nextfd), 0)
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 {
|
2011-04-02 15:24:03 -06:00
|
|
|
goto childerror
|
|
|
|
}
|
|
|
|
|
|
|
|
fd[i] = nextfd
|
|
|
|
nextfd++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pass 2: dup fd[i] down onto i.
|
|
|
|
for i = 0; i < len(fd); i++ {
|
|
|
|
if fd[i] == -1 {
|
|
|
|
RawSyscall(SYS_CLOSE, uintptr(i), 0, 0)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if fd[i] == int(i) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
r1, _, _ = RawSyscall(SYS_DUP, uintptr(fd[i]), uintptr(i), 0)
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 {
|
2011-04-02 15:24:03 -06:00
|
|
|
goto childerror
|
|
|
|
}
|
2012-04-16 18:35:15 -06:00
|
|
|
}
|
|
|
|
|
2012-04-26 03:59:13 -06:00
|
|
|
// Pass 3: close fd[i] if it was moved in the previous pass.
|
2012-04-16 18:35:15 -06:00
|
|
|
for i = 0; i < len(fd); i++ {
|
|
|
|
if fd[i] >= 0 && fd[i] != int(i) {
|
|
|
|
RawSyscall(SYS_CLOSE, uintptr(fd[i]), 0, 0)
|
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Time to exec.
|
|
|
|
r1, _, _ = RawSyscall(SYS_EXEC,
|
|
|
|
uintptr(unsafe.Pointer(argv0)),
|
|
|
|
uintptr(unsafe.Pointer(&argv[0])), 0)
|
|
|
|
|
|
|
|
childerror:
|
|
|
|
// send error string on pipe
|
|
|
|
RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&errbuf[0])), uintptr(len(errbuf)), 0)
|
2016-04-29 10:39:33 -06:00
|
|
|
childerror1:
|
2011-04-02 15:24:03 -06:00
|
|
|
errbuf[len(errbuf)-1] = 0
|
|
|
|
i = 0
|
|
|
|
for i < len(errbuf) && errbuf[i] != 0 {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
RawSyscall6(SYS_PWRITE, uintptr(pipe), uintptr(unsafe.Pointer(&errbuf[0])), uintptr(i),
|
|
|
|
^uintptr(0), ^uintptr(0), 0)
|
|
|
|
|
|
|
|
for {
|
|
|
|
RawSyscall(SYS_EXITS, 0, 0, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calling panic is not actually safe,
|
|
|
|
// but the for loop above won't break
|
|
|
|
// and this shuts up the compiler.
|
|
|
|
panic("unreached")
|
|
|
|
}
|
|
|
|
|
2016-04-29 10:39:33 -06:00
|
|
|
// close the numbered file descriptor, unless it is fd1, fd2, or a member of fds.
|
|
|
|
//go:nosplit
|
|
|
|
func closeFdExcept(n int, fd1 int, fd2 int, fds []int) {
|
|
|
|
if n == fd1 || n == fd2 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for _, fd := range fds {
|
|
|
|
if n == fd {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RawSyscall(SYS_CLOSE, uintptr(n), 0, 0)
|
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func cexecPipe(p []int) error {
|
2011-04-02 15:24:03 -06:00
|
|
|
e := Pipe(p)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
fd, e := Open("#d/"+itoa(p[1]), O_CLOEXEC)
|
|
|
|
if e != nil {
|
|
|
|
Close(p[0])
|
|
|
|
Close(p[1])
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
Close(fd)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type envItem struct {
|
|
|
|
name *byte
|
|
|
|
value *byte
|
|
|
|
nvalue int
|
|
|
|
}
|
|
|
|
|
|
|
|
type ProcAttr struct {
|
2012-02-16 12:04:51 -07:00
|
|
|
Dir string // Current working directory.
|
|
|
|
Env []string // Environment.
|
|
|
|
Files []uintptr // File descriptors.
|
2011-06-14 08:49:34 -06:00
|
|
|
Sys *SysProcAttr
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
2011-06-14 08:49:34 -06:00
|
|
|
type SysProcAttr struct {
|
|
|
|
Rfork int // additional flags to pass to rfork
|
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
|
2011-06-14 08:49:34 -06:00
|
|
|
var zeroProcAttr ProcAttr
|
|
|
|
var zeroSysProcAttr SysProcAttr
|
2011-04-02 15:24:03 -06:00
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
var (
|
|
|
|
p [2]int
|
|
|
|
n int
|
|
|
|
errbuf [ERRMAX]byte
|
|
|
|
wmsg Waitmsg
|
|
|
|
)
|
|
|
|
|
|
|
|
if attr == nil {
|
2011-06-14 08:49:34 -06:00
|
|
|
attr = &zeroProcAttr
|
|
|
|
}
|
|
|
|
sys := attr.Sys
|
|
|
|
if sys == nil {
|
|
|
|
sys = &zeroSysProcAttr
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
p[0] = -1
|
|
|
|
p[1] = -1
|
|
|
|
|
|
|
|
// Convert args to C form.
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
argv0p, err := BytePtrFromString(argv0)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
argvp, err := SlicePtrFromStrings(argv)
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
|
2015-02-27 20:34:56 -07:00
|
|
|
destDir := attr.Dir
|
|
|
|
if destDir == "" {
|
|
|
|
wdmu.Lock()
|
|
|
|
destDir = wdStr
|
|
|
|
wdmu.Unlock()
|
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
var dir *byte
|
2015-02-27 20:34:56 -07:00
|
|
|
if destDir != "" {
|
|
|
|
dir, err = BytePtrFromString(destDir)
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
var envvParsed []envItem
|
|
|
|
if attr.Env != nil {
|
|
|
|
envvParsed = make([]envItem, 0, len(attr.Env))
|
|
|
|
for _, v := range attr.Env {
|
|
|
|
i := 0
|
|
|
|
for i < len(v) && v[i] != '=' {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
envname, err := BytePtrFromString("/env/" + v[:i])
|
|
|
|
if err != nil {
|
|
|
|
return 0, err
|
|
|
|
}
|
2012-08-06 14:24:08 -06:00
|
|
|
envvalue := make([]byte, len(v)-i)
|
|
|
|
copy(envvalue, v[i+1:])
|
|
|
|
envvParsed = append(envvParsed, envItem{envname, &envvalue[0], len(v) - i})
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-30 14:38:01 -06:00
|
|
|
// Allocate child status pipe close on exec.
|
2016-04-29 10:39:33 -06:00
|
|
|
e := cexecPipe(p[:])
|
2011-04-02 15:24:03 -06:00
|
|
|
|
|
|
|
if e != nil {
|
|
|
|
return 0, e
|
|
|
|
}
|
|
|
|
|
|
|
|
// Kick off child.
|
2016-04-29 10:39:33 -06:00
|
|
|
pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, p[1], sys.Rfork)
|
2011-04-02 15:24:03 -06:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
if p[0] >= 0 {
|
|
|
|
Close(p[0])
|
|
|
|
Close(p[1])
|
|
|
|
}
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read child error status from pipe.
|
|
|
|
Close(p[1])
|
|
|
|
n, err = Read(p[0], errbuf[:])
|
|
|
|
Close(p[0])
|
|
|
|
|
|
|
|
if err != nil || n != 0 {
|
2016-04-29 10:39:33 -06:00
|
|
|
if n > 0 {
|
2014-02-19 18:17:36 -07:00
|
|
|
err = NewError(string(errbuf[:n]))
|
2016-04-29 10:39:33 -06:00
|
|
|
} else if err == nil {
|
|
|
|
err = NewError("failed to read exec status")
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Child failed; wait for it to exit, to make sure
|
|
|
|
// the zombies don't accumulate.
|
|
|
|
for wmsg.Pid != pid {
|
|
|
|
Await(&wmsg)
|
|
|
|
}
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read got EOF, so pipe closed on exec, so exec succeeded.
|
|
|
|
return pid, nil
|
|
|
|
}
|
|
|
|
|
syscall, os: fix a fork-exec/wait race in Plan 9.
On Plan 9, only the parent of a given process can enter its wait
queue. When a Go program tries to fork-exec a child process
and subsequently waits for it to finish, the goroutines doing
these two tasks do not necessarily tie themselves to the same
(or any single) OS thread. In the case that the fork and the wait
system calls happen on different OS threads (say, due to a
goroutine being rescheduled somewhere along the way), the
wait() will either return an error or end up waiting for a
completely different child than was intended.
This change forces the fork and wait syscalls to happen in the
same goroutine and ties that goroutine to its OS thread until
the child exits. The PID of the child is recorded upon fork and
exit, and de-queued once the child's wait message has been read.
The Wait API, then, is translated into a synthetic implementation
that simply waits for the requested PID to show up in the queue
and then reads the associated stats.
R=rsc, rminnich, npe, mirtchovski, ality
CC=golang-dev
https://golang.org/cl/6545051
2013-01-18 14:43:25 -07:00
|
|
|
type waitErr struct {
|
|
|
|
Waitmsg
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
|
|
|
var procs struct {
|
|
|
|
sync.Mutex
|
|
|
|
waits map[int]chan *waitErr
|
|
|
|
}
|
|
|
|
|
|
|
|
// startProcess starts a new goroutine, tied to the OS
|
|
|
|
// thread, which runs the process and subsequently waits
|
|
|
|
// for it to finish, communicating the process stats back
|
|
|
|
// to any goroutines that may have been waiting on it.
|
|
|
|
//
|
|
|
|
// Such a dedicated goroutine is needed because on
|
|
|
|
// Plan 9, only the parent thread can wait for a child,
|
|
|
|
// whereas goroutines tend to jump OS threads (e.g.,
|
|
|
|
// between starting a process and running Wait(), the
|
|
|
|
// goroutine may have been rescheduled).
|
|
|
|
func startProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
|
|
|
type forkRet struct {
|
|
|
|
pid int
|
|
|
|
err error
|
|
|
|
}
|
|
|
|
|
|
|
|
forkc := make(chan forkRet, 1)
|
|
|
|
go func() {
|
|
|
|
runtime.LockOSThread()
|
|
|
|
var ret forkRet
|
|
|
|
|
|
|
|
ret.pid, ret.err = forkExec(argv0, argv, attr)
|
|
|
|
// If fork fails there is nothing to wait for.
|
|
|
|
if ret.err != nil || ret.pid == 0 {
|
|
|
|
forkc <- ret
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
waitc := make(chan *waitErr, 1)
|
|
|
|
|
|
|
|
// Mark that the process is running.
|
|
|
|
procs.Lock()
|
|
|
|
if procs.waits == nil {
|
|
|
|
procs.waits = make(map[int]chan *waitErr)
|
|
|
|
}
|
|
|
|
procs.waits[ret.pid] = waitc
|
|
|
|
procs.Unlock()
|
|
|
|
|
|
|
|
forkc <- ret
|
|
|
|
|
|
|
|
var w waitErr
|
2013-01-22 20:42:44 -07:00
|
|
|
for w.err == nil && w.Pid != ret.pid {
|
|
|
|
w.err = Await(&w.Waitmsg)
|
|
|
|
}
|
syscall, os: fix a fork-exec/wait race in Plan 9.
On Plan 9, only the parent of a given process can enter its wait
queue. When a Go program tries to fork-exec a child process
and subsequently waits for it to finish, the goroutines doing
these two tasks do not necessarily tie themselves to the same
(or any single) OS thread. In the case that the fork and the wait
system calls happen on different OS threads (say, due to a
goroutine being rescheduled somewhere along the way), the
wait() will either return an error or end up waiting for a
completely different child than was intended.
This change forces the fork and wait syscalls to happen in the
same goroutine and ties that goroutine to its OS thread until
the child exits. The PID of the child is recorded upon fork and
exit, and de-queued once the child's wait message has been read.
The Wait API, then, is translated into a synthetic implementation
that simply waits for the requested PID to show up in the queue
and then reads the associated stats.
R=rsc, rminnich, npe, mirtchovski, ality
CC=golang-dev
https://golang.org/cl/6545051
2013-01-18 14:43:25 -07:00
|
|
|
waitc <- &w
|
|
|
|
close(waitc)
|
|
|
|
}()
|
|
|
|
ret := <-forkc
|
|
|
|
return ret.pid, ret.err
|
|
|
|
}
|
|
|
|
|
2013-01-22 20:42:44 -07:00
|
|
|
// Combination of fork and exec, careful to be thread safe.
|
|
|
|
func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
|
|
|
|
return startProcess(argv0, argv, attr)
|
|
|
|
}
|
|
|
|
|
2011-04-02 15:24:03 -06:00
|
|
|
// StartProcess wraps ForkExec for package os.
|
2012-02-02 12:08:48 -07:00
|
|
|
func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
|
syscall, os: fix a fork-exec/wait race in Plan 9.
On Plan 9, only the parent of a given process can enter its wait
queue. When a Go program tries to fork-exec a child process
and subsequently waits for it to finish, the goroutines doing
these two tasks do not necessarily tie themselves to the same
(or any single) OS thread. In the case that the fork and the wait
system calls happen on different OS threads (say, due to a
goroutine being rescheduled somewhere along the way), the
wait() will either return an error or end up waiting for a
completely different child than was intended.
This change forces the fork and wait syscalls to happen in the
same goroutine and ties that goroutine to its OS thread until
the child exits. The PID of the child is recorded upon fork and
exit, and de-queued once the child's wait message has been read.
The Wait API, then, is translated into a synthetic implementation
that simply waits for the requested PID to show up in the queue
and then reads the associated stats.
R=rsc, rminnich, npe, mirtchovski, ality
CC=golang-dev
https://golang.org/cl/6545051
2013-01-18 14:43:25 -07:00
|
|
|
pid, err = startProcess(argv0, argv, attr)
|
2011-04-02 15:24:03 -06:00
|
|
|
return pid, 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ordinary exec.
|
2011-11-16 15:37:54 -07:00
|
|
|
func Exec(argv0 string, argv []string, envv []string) (err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
if envv != nil {
|
|
|
|
r1, _, _ := RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r1) == -1 {
|
2011-04-02 15:24:03 -06:00
|
|
|
return NewError(errstr())
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range envv {
|
|
|
|
i := 0
|
|
|
|
for i < len(v) && v[i] != '=' {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
|
|
|
|
fd, e := Create("/env/"+v[:i], O_WRONLY, 0666)
|
|
|
|
if e != nil {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
|
|
|
_, e = Write(fd, []byte(v[i+1:]))
|
|
|
|
if e != nil {
|
|
|
|
Close(fd)
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
Close(fd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
argv0p, err := BytePtrFromString(argv0)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
argvp, err := SlicePtrFromStrings(argv)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2011-11-21 07:55:15 -07:00
|
|
|
_, _, e1 := Syscall(SYS_EXEC,
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
uintptr(unsafe.Pointer(argv0p)),
|
|
|
|
uintptr(unsafe.Pointer(&argvp[0])),
|
2011-04-02 15:24:03 -06:00
|
|
|
0)
|
|
|
|
|
2011-11-21 07:55:15 -07:00
|
|
|
return e1
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
syscall, os: fix a fork-exec/wait race in Plan 9.
On Plan 9, only the parent of a given process can enter its wait
queue. When a Go program tries to fork-exec a child process
and subsequently waits for it to finish, the goroutines doing
these two tasks do not necessarily tie themselves to the same
(or any single) OS thread. In the case that the fork and the wait
system calls happen on different OS threads (say, due to a
goroutine being rescheduled somewhere along the way), the
wait() will either return an error or end up waiting for a
completely different child than was intended.
This change forces the fork and wait syscalls to happen in the
same goroutine and ties that goroutine to its OS thread until
the child exits. The PID of the child is recorded upon fork and
exit, and de-queued once the child's wait message has been read.
The Wait API, then, is translated into a synthetic implementation
that simply waits for the requested PID to show up in the queue
and then reads the associated stats.
R=rsc, rminnich, npe, mirtchovski, ality
CC=golang-dev
https://golang.org/cl/6545051
2013-01-18 14:43:25 -07:00
|
|
|
|
|
|
|
// WaitProcess waits until the pid of a
|
|
|
|
// running process is found in the queue of
|
|
|
|
// wait messages. It is used in conjunction
|
2013-01-22 20:42:44 -07:00
|
|
|
// with ForkExec/StartProcess to wait for a
|
|
|
|
// running process to exit.
|
syscall, os: fix a fork-exec/wait race in Plan 9.
On Plan 9, only the parent of a given process can enter its wait
queue. When a Go program tries to fork-exec a child process
and subsequently waits for it to finish, the goroutines doing
these two tasks do not necessarily tie themselves to the same
(or any single) OS thread. In the case that the fork and the wait
system calls happen on different OS threads (say, due to a
goroutine being rescheduled somewhere along the way), the
wait() will either return an error or end up waiting for a
completely different child than was intended.
This change forces the fork and wait syscalls to happen in the
same goroutine and ties that goroutine to its OS thread until
the child exits. The PID of the child is recorded upon fork and
exit, and de-queued once the child's wait message has been read.
The Wait API, then, is translated into a synthetic implementation
that simply waits for the requested PID to show up in the queue
and then reads the associated stats.
R=rsc, rminnich, npe, mirtchovski, ality
CC=golang-dev
https://golang.org/cl/6545051
2013-01-18 14:43:25 -07:00
|
|
|
func WaitProcess(pid int, w *Waitmsg) (err error) {
|
|
|
|
procs.Lock()
|
|
|
|
ch := procs.waits[pid]
|
|
|
|
procs.Unlock()
|
|
|
|
|
|
|
|
var wmsg *waitErr
|
|
|
|
if ch != nil {
|
|
|
|
wmsg = <-ch
|
|
|
|
procs.Lock()
|
|
|
|
if procs.waits[pid] == ch {
|
|
|
|
delete(procs.waits, pid)
|
|
|
|
}
|
|
|
|
procs.Unlock()
|
|
|
|
}
|
|
|
|
if wmsg == nil {
|
|
|
|
// ch was missing or ch is closed
|
|
|
|
return NewError("process not found")
|
|
|
|
}
|
|
|
|
if wmsg.err != nil {
|
|
|
|
return wmsg.err
|
|
|
|
}
|
|
|
|
if w != nil {
|
|
|
|
*w = wmsg.Waitmsg
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|