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"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Lock synchronizing creation of new file descriptors with fork.
|
|
|
|
//
|
|
|
|
// We want the child in a fork/exec sequence to inherit only the
|
2016-03-01 16:21:55 -07:00
|
|
|
// file descriptors we intend. To do that, we mark all file
|
2011-04-02 15:24:03 -06:00
|
|
|
// descriptors close-on-exec and then, in the child, explicitly
|
|
|
|
// unmark the ones we want the exec'ed program to keep.
|
|
|
|
// Unix doesn't make this easy: there is, in general, no way to
|
2016-03-01 16:21:55 -07:00
|
|
|
// allocate a new file descriptor close-on-exec. Instead you
|
2011-04-02 15:24:03 -06:00
|
|
|
// have to allocate the descriptor and then mark it close-on-exec.
|
|
|
|
// If a fork happens between those two events, the child's exec
|
|
|
|
// will inherit an unwanted file descriptor.
|
|
|
|
//
|
|
|
|
// This lock solves that race: the create new fd/mark close-on-exec
|
|
|
|
// operation is done holding ForkLock for reading, and the fork itself
|
2016-03-01 16:21:55 -07:00
|
|
|
// is done holding ForkLock for writing. At least, that's the idea.
|
2011-04-02 15:24:03 -06:00
|
|
|
// There are some complications.
|
|
|
|
//
|
|
|
|
// Some system calls that create new file descriptors can block
|
|
|
|
// for arbitrarily long times: open on a hung NFS server or named
|
2016-03-01 16:21:55 -07:00
|
|
|
// pipe, accept on a socket, and so on. We can't reasonably grab
|
2011-04-02 15:24:03 -06:00
|
|
|
// the lock across those operations.
|
|
|
|
//
|
|
|
|
// It is worse to inherit some file descriptors than others.
|
|
|
|
// If a non-malicious child accidentally inherits an open ordinary file,
|
2016-03-01 16:21:55 -07:00
|
|
|
// that's not a big deal. On the other hand, if a long-lived child
|
2011-04-02 15:24:03 -06:00
|
|
|
// accidentally inherits the write end of a pipe, then the reader
|
|
|
|
// of that pipe will not see EOF until that child exits, potentially
|
2016-03-01 16:21:55 -07:00
|
|
|
// causing the parent program to hang. This is a common problem
|
2011-04-02 15:24:03 -06:00
|
|
|
// in threaded C programs that use popen.
|
|
|
|
//
|
|
|
|
// Luckily, the file descriptors that are most important not to
|
|
|
|
// inherit are not the ones that can take an arbitrarily long time
|
|
|
|
// to create: pipe returns instantly, and the net package uses
|
|
|
|
// non-blocking I/O to accept on a listening socket.
|
|
|
|
// The rules for which file descriptor-creating operations use the
|
|
|
|
// ForkLock are as follows:
|
|
|
|
//
|
2016-03-01 16:21:55 -07:00
|
|
|
// 1) Pipe. Does not block. Use the ForkLock.
|
|
|
|
// 2) Socket. Does not block. Use the ForkLock.
|
|
|
|
// 3) Accept. If using non-blocking mode, use the ForkLock.
|
2011-04-02 15:24:03 -06:00
|
|
|
// Otherwise, live with the race.
|
2016-03-01 16:21:55 -07:00
|
|
|
// 4) Open. Can block. Use O_CLOEXEC if available (Linux).
|
2011-04-02 15:24:03 -06:00
|
|
|
// Otherwise, live with the race.
|
2016-03-01 16:21:55 -07:00
|
|
|
// 5) Dup. Does not block. Use the ForkLock.
|
2011-04-02 15:24:03 -06:00
|
|
|
// On Linux, could use fcntl F_DUPFD_CLOEXEC
|
|
|
|
// instead of the ForkLock, but only for dup(fd, -1).
|
|
|
|
|
|
|
|
var ForkLock sync.RWMutex
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
for i := 0; i < n; {
|
|
|
|
m, _ := gbit16(buf[i:])
|
|
|
|
m += 2
|
|
|
|
|
|
|
|
if m < STATFIXLEN {
|
2012-11-26 16:26:46 -07:00
|
|
|
return nil, ErrBadStat
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
2012-11-26 16:26:46 -07:00
|
|
|
s, _, ok := gstring(buf[i+41:])
|
|
|
|
if !ok {
|
|
|
|
return nil, ErrBadStat
|
|
|
|
}
|
2012-04-26 03:59:13 -06:00
|
|
|
names = append(names, s)
|
2011-04-02 15:24:03 -06:00
|
|
|
i += int(m)
|
|
|
|
}
|
|
|
|
}
|
2012-04-26 03:59:13 -06:00
|
|
|
return
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d.
|
|
|
|
// ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read.
|
2011-11-16 15:37:54 -07:00
|
|
|
func readdupdevice() (fds []int, err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
dupdevfd, err := Open("#d", O_RDONLY)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer Close(dupdevfd)
|
|
|
|
|
2012-04-26 03:59:13 -06:00
|
|
|
names, err := readdirnames(dupdevfd)
|
2011-04-02 15:24:03 -06:00
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2012-04-26 03:59:13 -06:00
|
|
|
fds = make([]int, 0, len(names)/2)
|
|
|
|
for _, name := range names {
|
|
|
|
if n := len(name); n > 3 && name[n-3:n] == "ctl" {
|
2011-04-02 15:24:03 -06:00
|
|
|
continue
|
|
|
|
}
|
2012-04-26 03:59:13 -06:00
|
|
|
fd := int(atoi([]byte(name)))
|
|
|
|
switch fd {
|
|
|
|
case 0, 1, 2, dupdevfd:
|
2011-04-02 15:24:03 -06:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
fds = append(fds, fd)
|
|
|
|
}
|
2012-04-26 03:59:13 -06:00
|
|
|
return
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
var startupFds []int
|
|
|
|
|
|
|
|
// Plan 9 does not allow clearing the OCEXEC flag
|
|
|
|
// from the underlying channel backing an open file descriptor,
|
|
|
|
// therefore we store a list of already opened file descriptors
|
|
|
|
// inside startupFds and skip them when manually closing descriptors
|
|
|
|
// not meant to be passed to a child exec.
|
|
|
|
func init() {
|
|
|
|
startupFds, _ = readdupdevice()
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2011-11-16 15:37:54 -07:00
|
|
|
func forkAndExecInChild(argv0 *byte, argv []*byte, envv []envItem, dir *byte, attr *ProcAttr, fdsToClose []int, 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
|
|
|
|
)
|
|
|
|
|
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.
|
|
|
|
for i = 0; i < len(fdsToClose); i++ {
|
2016-03-17 04:20:54 -06:00
|
|
|
if fdsToClose[i] != pipe {
|
|
|
|
RawSyscall(SYS_CLOSE, uintptr(fdsToClose[i]), 0, 0)
|
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if envv != nil {
|
|
|
|
// Write new environment variables.
|
|
|
|
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) {
|
|
|
|
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++
|
|
|
|
if nextfd == pipe { // don't stomp on pipe
|
|
|
|
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)
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Acquire the fork lock to prevent other threads from creating new fds before we fork.
|
|
|
|
ForkLock.Lock()
|
|
|
|
|
|
|
|
// get a list of open fds, excluding stdin,stdout and stderr that need to be closed in the child.
|
|
|
|
// no new fds can be created while we hold the ForkLock for writing.
|
|
|
|
openFds, e := readdupdevice()
|
|
|
|
if e != nil {
|
|
|
|
ForkLock.Unlock()
|
|
|
|
return 0, e
|
|
|
|
}
|
|
|
|
|
|
|
|
fdsToClose := make([]int, 0, len(openFds))
|
|
|
|
for _, fd := range openFds {
|
2012-04-26 03:59:13 -06:00
|
|
|
doClose := true
|
|
|
|
|
|
|
|
// exclude files opened at startup.
|
|
|
|
for _, sfd := range startupFds {
|
|
|
|
if fd == sfd {
|
|
|
|
doClose = false
|
2011-04-02 15:24:03 -06:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-26 03:59:13 -06:00
|
|
|
// exclude files explicitly requested by the caller.
|
|
|
|
for _, rfd := range attr.Files {
|
|
|
|
if fd == int(rfd) {
|
|
|
|
doClose = false
|
2011-04-02 15:24:03 -06:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-04-26 03:59:13 -06:00
|
|
|
if doClose {
|
2011-04-02 15:24:03 -06:00
|
|
|
fdsToClose = append(fdsToClose, fd)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-30 14:38:01 -06:00
|
|
|
// Allocate child status pipe close on exec.
|
2011-04-02 15:24:03 -06:00
|
|
|
e = cexecPipe(p[:])
|
|
|
|
|
|
|
|
if e != nil {
|
|
|
|
return 0, e
|
|
|
|
}
|
|
|
|
fdsToClose = append(fdsToClose, p[0])
|
|
|
|
|
|
|
|
// Kick off child.
|
2011-06-14 08:49:34 -06:00
|
|
|
pid, err = forkAndExecInChild(argv0p, argvp, envvParsed, dir, attr, fdsToClose, 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])
|
|
|
|
}
|
|
|
|
ForkLock.Unlock()
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
ForkLock.Unlock()
|
|
|
|
|
|
|
|
// Read child error status from pipe.
|
|
|
|
Close(p[1])
|
|
|
|
n, err = Read(p[0], errbuf[:])
|
|
|
|
Close(p[0])
|
|
|
|
|
|
|
|
if err != nil || n != 0 {
|
|
|
|
if n != 0 {
|
2014-02-19 18:17:36 -07:00
|
|
|
err = NewError(string(errbuf[:n]))
|
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
|
|
|
|
}
|