exec_libc2.mx raw

   1  // Copyright 2011 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 darwin || (openbsd && !mips64)
   6  
   7  package syscall
   8  
   9  import (
  10  	"internal/abi"
  11  	"runtime"
  12  	"unsafe"
  13  )
  14  
  15  type SysProcAttr struct {
  16  	Chroot     string      // Chroot.
  17  	Credential *Credential // Credential.
  18  	Ptrace     bool        // Enable tracing.
  19  	Setsid     bool        // Create session.
  20  	// Setpgid sets the process group ID of the child to Pgid,
  21  	// or, if Pgid == 0, to the new child's process ID.
  22  	Setpgid bool
  23  	// Setctty sets the controlling terminal of the child to
  24  	// file descriptor Ctty. Ctty must be a descriptor number
  25  	// in the child process: an index into ProcAttr.Files.
  26  	// This is only meaningful if Setsid is true.
  27  	Setctty bool
  28  	Noctty  bool // Detach fd 0 from controlling terminal
  29  	Ctty    int  // Controlling TTY fd
  30  	// Foreground places the child process group in the foreground.
  31  	// This implies Setpgid. The Ctty field must be set to
  32  	// the descriptor of the controlling TTY.
  33  	// Unlike Setctty, in this case Ctty must be a descriptor
  34  	// number in the parent process.
  35  	Foreground bool
  36  	Pgid       int // Child's process group ID if Setpgid.
  37  }
  38  
  39  // Implemented in runtime package.
  40  func runtime_BeforeFork()
  41  func runtime_AfterFork()
  42  func runtime_AfterForkInChild()
  43  
  44  // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child.
  45  // If a dup or exec fails, write the errno error to pipe.
  46  // (Pipe is close-on-exec so if exec succeeds, it will be closed.)
  47  // In the child, this function must not acquire any locks, because
  48  // they might have been locked at the time of the fork. This means
  49  // no rescheduling, no malloc calls, and no new stack segments.
  50  // For the same reason compiler does not race instrument it.
  51  // The calls to rawSyscall are okay because they are assembly
  52  // functions that do not grow the stack.
  53  //
  54  //go:norace
  55  func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err1 Errno) {
  56  	// Declare all variables at top in case any
  57  	// declarations require heap allocation (e.g., err1).
  58  	var (
  59  		r1              uintptr
  60  		nextfd          int
  61  		i               int
  62  		err             error
  63  		pgrp            _C_int
  64  		cred            *Credential
  65  		ngroups, groups uintptr
  66  	)
  67  
  68  	rlim := origRlimitNofile.Load()
  69  
  70  	// guard against side effects of shuffling fds below.
  71  	// Make sure that nextfd is beyond any currently open files so
  72  	// that we can't run the risk of overwriting any of them.
  73  	fd := make([]int, len(attr.Files))
  74  	nextfd = len(attr.Files)
  75  	for i, ufd := range attr.Files {
  76  		if nextfd < int(ufd) {
  77  			nextfd = int(ufd)
  78  		}
  79  		fd[i] = int(ufd)
  80  	}
  81  	nextfd++
  82  
  83  	// About to call fork.
  84  	// No more allocation or calls of non-assembly functions.
  85  	runtime_BeforeFork()
  86  	r1, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0)
  87  	if err1 != 0 {
  88  		runtime_AfterFork()
  89  		return 0, err1
  90  	}
  91  
  92  	if r1 != 0 {
  93  		// parent; return PID
  94  		runtime_AfterFork()
  95  		return int(r1), 0
  96  	}
  97  
  98  	// Fork succeeded, now in child.
  99  
 100  	// Enable tracing if requested.
 101  	if sys.Ptrace {
 102  		if err = ptrace(PTRACE_TRACEME, 0, 0, 0); err != nil {
 103  			err1 = err.(Errno)
 104  			goto childerror
 105  		}
 106  	}
 107  
 108  	// Session ID
 109  	if sys.Setsid {
 110  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setsid_trampoline), 0, 0, 0)
 111  		if err1 != 0 {
 112  			goto childerror
 113  		}
 114  	}
 115  
 116  	// Set process group
 117  	if sys.Setpgid || sys.Foreground {
 118  		// Place child in process group.
 119  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setpgid_trampoline), 0, uintptr(sys.Pgid), 0)
 120  		if err1 != 0 {
 121  			goto childerror
 122  		}
 123  	}
 124  
 125  	if sys.Foreground {
 126  		// This should really be pid_t, however _C_int (aka int32) is
 127  		// generally equivalent.
 128  		pgrp = _C_int(sys.Pgid)
 129  		if pgrp == 0 {
 130  			r1, _, err1 = rawSyscall(abi.FuncPCABI0(libc_getpid_trampoline), 0, 0, 0)
 131  			if err1 != 0 {
 132  				goto childerror
 133  			}
 134  			pgrp = _C_int(r1)
 135  		}
 136  
 137  		// Place process group in foreground.
 138  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
 139  		if err1 != 0 {
 140  			goto childerror
 141  		}
 142  	}
 143  
 144  	// Restore the signal mask. We do this after TIOCSPGRP to avoid
 145  	// having the kernel send a SIGTTOU signal to the process group.
 146  	runtime_AfterForkInChild()
 147  
 148  	// Chroot
 149  	if chroot != nil {
 150  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_chroot_trampoline), uintptr(unsafe.Pointer(chroot)), 0, 0)
 151  		if err1 != 0 {
 152  			goto childerror
 153  		}
 154  	}
 155  
 156  	// User and groups
 157  	if cred = sys.Credential; cred != nil {
 158  		ngroups = uintptr(len(cred.Groups))
 159  		groups = uintptr(0)
 160  		if ngroups > 0 {
 161  			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
 162  		}
 163  		if !cred.NoSetGroups {
 164  			_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setgroups_trampoline), ngroups, groups, 0)
 165  			if err1 != 0 {
 166  				goto childerror
 167  			}
 168  		}
 169  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setgid_trampoline), uintptr(cred.Gid), 0, 0)
 170  		if err1 != 0 {
 171  			goto childerror
 172  		}
 173  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setuid_trampoline), uintptr(cred.Uid), 0, 0)
 174  		if err1 != 0 {
 175  			goto childerror
 176  		}
 177  	}
 178  
 179  	// Chdir
 180  	if dir != nil {
 181  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_chdir_trampoline), uintptr(unsafe.Pointer(dir)), 0, 0)
 182  		if err1 != 0 {
 183  			goto childerror
 184  		}
 185  	}
 186  
 187  	// Pass 1: look for fd[i] < i and move those up above len(fd)
 188  	// so that pass 2 won't stomp on an fd it needs later.
 189  	if pipe < nextfd {
 190  		if runtime.GOOS == "openbsd" {
 191  			_, _, err1 = rawSyscall(dupTrampoline, uintptr(pipe), uintptr(nextfd), O_CLOEXEC)
 192  		} else {
 193  			_, _, err1 = rawSyscall(dupTrampoline, uintptr(pipe), uintptr(nextfd), 0)
 194  			if err1 != 0 {
 195  				goto childerror
 196  			}
 197  			_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC)
 198  		}
 199  		if err1 != 0 {
 200  			goto childerror
 201  		}
 202  		pipe = nextfd
 203  		nextfd++
 204  	}
 205  	for i = 0; i < len(fd); i++ {
 206  		if fd[i] >= 0 && fd[i] < i {
 207  			if nextfd == pipe { // don't stomp on pipe
 208  				nextfd++
 209  			}
 210  			if runtime.GOOS == "openbsd" {
 211  				_, _, err1 = rawSyscall(dupTrampoline, uintptr(fd[i]), uintptr(nextfd), O_CLOEXEC)
 212  			} else {
 213  				_, _, err1 = rawSyscall(dupTrampoline, uintptr(fd[i]), uintptr(nextfd), 0)
 214  				if err1 != 0 {
 215  					goto childerror
 216  				}
 217  				_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC)
 218  			}
 219  			if err1 != 0 {
 220  				goto childerror
 221  			}
 222  			fd[i] = nextfd
 223  			nextfd++
 224  		}
 225  	}
 226  
 227  	// Pass 2: dup fd[i] down onto i.
 228  	for i = 0; i < len(fd); i++ {
 229  		if fd[i] == -1 {
 230  			rawSyscall(abi.FuncPCABI0(libc_close_trampoline), uintptr(i), 0, 0)
 231  			continue
 232  		}
 233  		if fd[i] == i {
 234  			// dup2(i, i) won't clear close-on-exec flag on Linux,
 235  			// probably not elsewhere either.
 236  			_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(fd[i]), F_SETFD, 0)
 237  			if err1 != 0 {
 238  				goto childerror
 239  			}
 240  			continue
 241  		}
 242  		// The new fd is created NOT close-on-exec,
 243  		// which is exactly what we want.
 244  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(fd[i]), uintptr(i), 0)
 245  		if err1 != 0 {
 246  			goto childerror
 247  		}
 248  	}
 249  
 250  	// By convention, we don't close-on-exec the fds we are
 251  	// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
 252  	// Programs that know they inherit fds >= 3 will need
 253  	// to set them close-on-exec.
 254  	for i = len(fd); i < 3; i++ {
 255  		rawSyscall(abi.FuncPCABI0(libc_close_trampoline), uintptr(i), 0, 0)
 256  	}
 257  
 258  	// Detach fd 0 from tty
 259  	if sys.Noctty {
 260  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), 0, uintptr(TIOCNOTTY), 0)
 261  		if err1 != 0 {
 262  			goto childerror
 263  		}
 264  	}
 265  
 266  	// Set the controlling TTY to Ctty
 267  	if sys.Setctty {
 268  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
 269  		if err1 != 0 {
 270  			goto childerror
 271  		}
 272  	}
 273  
 274  	// Restore original rlimit.
 275  	if rlim != nil {
 276  		rawSyscall(abi.FuncPCABI0(libc_setrlimit_trampoline), uintptr(RLIMIT_NOFILE), uintptr(unsafe.Pointer(rlim)), 0)
 277  	}
 278  
 279  	// Time to exec.
 280  	_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_execve_trampoline),
 281  		uintptr(unsafe.Pointer(argv0)),
 282  		uintptr(unsafe.Pointer(&argv[0])),
 283  		uintptr(unsafe.Pointer(&envv[0])))
 284  
 285  childerror:
 286  	// send error code on pipe
 287  	rawSyscall(abi.FuncPCABI0(libc_write_trampoline), uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
 288  	for {
 289  		rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), 253, 0, 0)
 290  	}
 291  }
 292  
 293  // forkAndExecFailureCleanup cleans up after an exec failure.
 294  func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) {
 295  	// Nothing to do.
 296  }
 297