...

Source file src/pkg/syscall/exec_unix.go

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

View as plain text