...

Source file src/syscall/exec_unix.go

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

View as plain text