Home | History | Annotate | Download | only in syscall
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // +build darwin dragonfly freebsd linux netbsd openbsd solaris
      6 
      7 // Fork, exec, wait, etc.
      8 
      9 package syscall
     10 
     11 import (
     12 	"runtime"
     13 	"sync"
     14 	"unsafe"
     15 )
     16 
     17 // Lock synchronizing creation of new file descriptors with fork.
     18 //
     19 // We want the child in a fork/exec sequence to inherit only the
     20 // file descriptors we intend.  To do that, we mark all file
     21 // descriptors close-on-exec and then, in the child, explicitly
     22 // unmark the ones we want the exec'ed program to keep.
     23 // Unix doesn't make this easy: there is, in general, no way to
     24 // allocate a new file descriptor close-on-exec.  Instead you
     25 // have to allocate the descriptor and then mark it close-on-exec.
     26 // If a fork happens between those two events, the child's exec
     27 // will inherit an unwanted file descriptor.
     28 //
     29 // This lock solves that race: the create new fd/mark close-on-exec
     30 // operation is done holding ForkLock for reading, and the fork itself
     31 // is done holding ForkLock for writing.  At least, that's the idea.
     32 // There are some complications.
     33 //
     34 // Some system calls that create new file descriptors can block
     35 // for arbitrarily long times: open on a hung NFS server or named
     36 // pipe, accept on a socket, and so on.  We can't reasonably grab
     37 // the lock across those operations.
     38 //
     39 // It is worse to inherit some file descriptors than others.
     40 // If a non-malicious child accidentally inherits an open ordinary file,
     41 // that's not a big deal.  On the other hand, if a long-lived child
     42 // accidentally inherits the write end of a pipe, then the reader
     43 // of that pipe will not see EOF until that child exits, potentially
     44 // causing the parent program to hang.  This is a common problem
     45 // in threaded C programs that use popen.
     46 //
     47 // Luckily, the file descriptors that are most important not to
     48 // inherit are not the ones that can take an arbitrarily long time
     49 // to create: pipe returns instantly, and the net package uses
     50 // non-blocking I/O to accept on a listening socket.
     51 // The rules for which file descriptor-creating operations use the
     52 // ForkLock are as follows:
     53 //
     54 // 1) Pipe.    Does not block.  Use the ForkLock.
     55 // 2) Socket.  Does not block.  Use the ForkLock.
     56 // 3) Accept.  If using non-blocking mode, use the ForkLock.
     57 //             Otherwise, live with the race.
     58 // 4) Open.    Can block.  Use O_CLOEXEC if available (Linux).
     59 //             Otherwise, live with the race.
     60 // 5) Dup.     Does not block.  Use the ForkLock.
     61 //             On Linux, could use fcntl F_DUPFD_CLOEXEC
     62 //             instead of the ForkLock, but only for dup(fd, -1).
     63 
     64 var ForkLock sync.RWMutex
     65 
     66 // StringSlicePtr converts a slice of strings to a slice of pointers
     67 // to NUL-terminated byte arrays. If any string contains a NUL byte
     68 // this function panics instead of returning an error.
     69 //
     70 // Deprecated: Use SlicePtrFromStrings instead.
     71 func StringSlicePtr(ss []string) []*byte {
     72 	bb := make([]*byte, len(ss)+1)
     73 	for i := 0; i < len(ss); i++ {
     74 		bb[i] = StringBytePtr(ss[i])
     75 	}
     76 	bb[len(ss)] = nil
     77 	return bb
     78 }
     79 
     80 // SlicePtrFromStrings converts a slice of strings to a slice of
     81 // pointers to NUL-terminated byte arrays. If any string contains
     82 // a NUL byte, it returns (nil, EINVAL).
     83 func SlicePtrFromStrings(ss []string) ([]*byte, error) {
     84 	var err error
     85 	bb := make([]*byte, len(ss)+1)
     86 	for i := 0; i < len(ss); i++ {
     87 		bb[i], err = BytePtrFromString(ss[i])
     88 		if err != nil {
     89 			return nil, err
     90 		}
     91 	}
     92 	bb[len(ss)] = nil
     93 	return bb, nil
     94 }
     95 
     96 func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
     97 
     98 func SetNonblock(fd int, nonblocking bool) (err error) {
     99 	flag, err := fcntl(fd, F_GETFL, 0)
    100 	if err != nil {
    101 		return err
    102 	}
    103 	if nonblocking {
    104 		flag |= O_NONBLOCK
    105 	} else {
    106 		flag &= ^O_NONBLOCK
    107 	}
    108 	_, err = fcntl(fd, F_SETFL, flag)
    109 	return err
    110 }
    111 
    112 // Credential holds user and group identities to be assumed
    113 // by a child process started by StartProcess.
    114 type Credential struct {
    115 	Uid    uint32   // User ID.
    116 	Gid    uint32   // Group ID.
    117 	Groups []uint32 // Supplementary group IDs.
    118 }
    119 
    120 // ProcAttr holds attributes that will be applied to a new process started
    121 // by StartProcess.
    122 type ProcAttr struct {
    123 	Dir   string    // Current working directory.
    124 	Env   []string  // Environment.
    125 	Files []uintptr // File descriptors.
    126 	Sys   *SysProcAttr
    127 }
    128 
    129 var zeroProcAttr ProcAttr
    130 var zeroSysProcAttr SysProcAttr
    131 
    132 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
    133 	var p [2]int
    134 	var n int
    135 	var err1 Errno
    136 	var wstatus WaitStatus
    137 
    138 	if attr == nil {
    139 		attr = &zeroProcAttr
    140 	}
    141 	sys := attr.Sys
    142 	if sys == nil {
    143 		sys = &zeroSysProcAttr
    144 	}
    145 
    146 	p[0] = -1
    147 	p[1] = -1
    148 
    149 	// Convert args to C form.
    150 	argv0p, err := BytePtrFromString(argv0)
    151 	if err != nil {
    152 		return 0, err
    153 	}
    154 	argvp, err := SlicePtrFromStrings(argv)
    155 	if err != nil {
    156 		return 0, err
    157 	}
    158 	envvp, err := SlicePtrFromStrings(attr.Env)
    159 	if err != nil {
    160 		return 0, err
    161 	}
    162 
    163 	if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) {
    164 		argvp[0] = argv0p
    165 	}
    166 
    167 	var chroot *byte
    168 	if sys.Chroot != "" {
    169 		chroot, err = BytePtrFromString(sys.Chroot)
    170 		if err != nil {
    171 			return 0, err
    172 		}
    173 	}
    174 	var dir *byte
    175 	if attr.Dir != "" {
    176 		dir, err = BytePtrFromString(attr.Dir)
    177 		if err != nil {
    178 			return 0, err
    179 		}
    180 	}
    181 
    182 	// Acquire the fork lock so that no other threads
    183 	// create new fds that are not yet close-on-exec
    184 	// before we fork.
    185 	ForkLock.Lock()
    186 
    187 	// Allocate child status pipe close on exec.
    188 	if err = forkExecPipe(p[:]); err != nil {
    189 		goto error
    190 	}
    191 
    192 	// Kick off child.
    193 	pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
    194 	if err1 != 0 {
    195 		err = Errno(err1)
    196 		goto error
    197 	}
    198 	ForkLock.Unlock()
    199 
    200 	// Read child error status from pipe.
    201 	Close(p[1])
    202 	n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
    203 	Close(p[0])
    204 	if err != nil || n != 0 {
    205 		if n == int(unsafe.Sizeof(err1)) {
    206 			err = Errno(err1)
    207 		}
    208 		if err == nil {
    209 			err = EPIPE
    210 		}
    211 
    212 		// Child failed; wait for it to exit, to make sure
    213 		// the zombies don't accumulate.
    214 		_, err1 := Wait4(pid, &wstatus, 0, nil)
    215 		for err1 == EINTR {
    216 			_, err1 = Wait4(pid, &wstatus, 0, nil)
    217 		}
    218 		return 0, err
    219 	}
    220 
    221 	// Read got EOF, so pipe closed on exec, so exec succeeded.
    222 	return pid, nil
    223 
    224 error:
    225 	if p[0] >= 0 {
    226 		Close(p[0])
    227 		Close(p[1])
    228 	}
    229 	ForkLock.Unlock()
    230 	return 0, err
    231 }
    232 
    233 // Combination of fork and exec, careful to be thread safe.
    234 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) {
    235 	return forkExec(argv0, argv, attr)
    236 }
    237 
    238 // StartProcess wraps ForkExec for package os.
    239 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
    240 	pid, err = forkExec(argv0, argv, attr)
    241 	return pid, 0, err
    242 }
    243 
    244 // Ordinary exec.
    245 func Exec(argv0 string, argv []string, envv []string) (err error) {
    246 	argv0p, err := BytePtrFromString(argv0)
    247 	if err != nil {
    248 		return err
    249 	}
    250 	argvp, err := SlicePtrFromStrings(argv)
    251 	if err != nil {
    252 		return err
    253 	}
    254 	envvp, err := SlicePtrFromStrings(envv)
    255 	if err != nil {
    256 		return err
    257 	}
    258 	_, _, err1 := RawSyscall(SYS_EXECVE,
    259 		uintptr(unsafe.Pointer(argv0p)),
    260 		uintptr(unsafe.Pointer(&argvp[0])),
    261 		uintptr(unsafe.Pointer(&envvp[0])))
    262 	return Errno(err1)
    263 }
    264