...

Source file src/syscall/exec_libc2.go

Documentation: syscall

		 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
		 6  // +build darwin openbsd
		 7  
		 8  package syscall
		 9  
		10  import (
		11  	"internal/abi"
		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  //go:norace
		54  func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) {
		55  	// Declare all variables at top in case any
		56  	// declarations require heap allocation (e.g., err1).
		57  	var (
		58  		r1		 uintptr
		59  		err1	 Errno
		60  		nextfd int
		61  		i			int
		62  	)
		63  
		64  	// guard against side effects of shuffling fds below.
		65  	// Make sure that nextfd is beyond any currently open files so
		66  	// that we can't run the risk of overwriting any of them.
		67  	fd := make([]int, len(attr.Files))
		68  	nextfd = len(attr.Files)
		69  	for i, ufd := range attr.Files {
		70  		if nextfd < int(ufd) {
		71  			nextfd = int(ufd)
		72  		}
		73  		fd[i] = int(ufd)
		74  	}
		75  	nextfd++
		76  
		77  	// About to call fork.
		78  	// No more allocation or calls of non-assembly functions.
		79  	runtime_BeforeFork()
		80  	r1, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fork_trampoline), 0, 0, 0)
		81  	if err1 != 0 {
		82  		runtime_AfterFork()
		83  		return 0, err1
		84  	}
		85  
		86  	if r1 != 0 {
		87  		// parent; return PID
		88  		runtime_AfterFork()
		89  		return int(r1), 0
		90  	}
		91  
		92  	// Fork succeeded, now in child.
		93  
		94  	// Enable tracing if requested.
		95  	if sys.Ptrace {
		96  		if err := ptrace(PTRACE_TRACEME, 0, 0, 0); err != nil {
		97  			err1 = err.(Errno)
		98  			goto childerror
		99  		}
	 100  	}
	 101  
	 102  	// Session ID
	 103  	if sys.Setsid {
	 104  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setsid_trampoline), 0, 0, 0)
	 105  		if err1 != 0 {
	 106  			goto childerror
	 107  		}
	 108  	}
	 109  
	 110  	// Set process group
	 111  	if sys.Setpgid || sys.Foreground {
	 112  		// Place child in process group.
	 113  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setpgid_trampoline), 0, uintptr(sys.Pgid), 0)
	 114  		if err1 != 0 {
	 115  			goto childerror
	 116  		}
	 117  	}
	 118  
	 119  	if sys.Foreground {
	 120  		// This should really be pid_t, however _C_int (aka int32) is
	 121  		// generally equivalent.
	 122  		pgrp := _C_int(sys.Pgid)
	 123  		if pgrp == 0 {
	 124  			r1, _, err1 = rawSyscall(abi.FuncPCABI0(libc_getpid_trampoline), 0, 0, 0)
	 125  			if err1 != 0 {
	 126  				goto childerror
	 127  			}
	 128  			pgrp = _C_int(r1)
	 129  		}
	 130  
	 131  		// Place process group in foreground.
	 132  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
	 133  		if err1 != 0 {
	 134  			goto childerror
	 135  		}
	 136  	}
	 137  
	 138  	// Restore the signal mask. We do this after TIOCSPGRP to avoid
	 139  	// having the kernel send a SIGTTOU signal to the process group.
	 140  	runtime_AfterForkInChild()
	 141  
	 142  	// Chroot
	 143  	if chroot != nil {
	 144  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_chroot_trampoline), uintptr(unsafe.Pointer(chroot)), 0, 0)
	 145  		if err1 != 0 {
	 146  			goto childerror
	 147  		}
	 148  	}
	 149  
	 150  	// User and groups
	 151  	if cred := sys.Credential; cred != nil {
	 152  		ngroups := uintptr(len(cred.Groups))
	 153  		groups := uintptr(0)
	 154  		if ngroups > 0 {
	 155  			groups = uintptr(unsafe.Pointer(&cred.Groups[0]))
	 156  		}
	 157  		if !cred.NoSetGroups {
	 158  			_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setgroups_trampoline), ngroups, groups, 0)
	 159  			if err1 != 0 {
	 160  				goto childerror
	 161  			}
	 162  		}
	 163  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setgid_trampoline), uintptr(cred.Gid), 0, 0)
	 164  		if err1 != 0 {
	 165  			goto childerror
	 166  		}
	 167  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setuid_trampoline), uintptr(cred.Uid), 0, 0)
	 168  		if err1 != 0 {
	 169  			goto childerror
	 170  		}
	 171  	}
	 172  
	 173  	// Chdir
	 174  	if dir != nil {
	 175  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_chdir_trampoline), uintptr(unsafe.Pointer(dir)), 0, 0)
	 176  		if err1 != 0 {
	 177  			goto childerror
	 178  		}
	 179  	}
	 180  
	 181  	// Pass 1: look for fd[i] < i and move those up above len(fd)
	 182  	// so that pass 2 won't stomp on an fd it needs later.
	 183  	if pipe < nextfd {
	 184  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(pipe), uintptr(nextfd), 0)
	 185  		if err1 != 0 {
	 186  			goto childerror
	 187  		}
	 188  		rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC)
	 189  		pipe = nextfd
	 190  		nextfd++
	 191  	}
	 192  	for i = 0; i < len(fd); i++ {
	 193  		if fd[i] >= 0 && fd[i] < int(i) {
	 194  			if nextfd == pipe { // don't stomp on pipe
	 195  				nextfd++
	 196  			}
	 197  			_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(fd[i]), uintptr(nextfd), 0)
	 198  			if err1 != 0 {
	 199  				goto childerror
	 200  			}
	 201  			rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC)
	 202  			fd[i] = nextfd
	 203  			nextfd++
	 204  		}
	 205  	}
	 206  
	 207  	// Pass 2: dup fd[i] down onto i.
	 208  	for i = 0; i < len(fd); i++ {
	 209  		if fd[i] == -1 {
	 210  			rawSyscall(abi.FuncPCABI0(libc_close_trampoline), uintptr(i), 0, 0)
	 211  			continue
	 212  		}
	 213  		if fd[i] == int(i) {
	 214  			// dup2(i, i) won't clear close-on-exec flag on Linux,
	 215  			// probably not elsewhere either.
	 216  			_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(fd[i]), F_SETFD, 0)
	 217  			if err1 != 0 {
	 218  				goto childerror
	 219  			}
	 220  			continue
	 221  		}
	 222  		// The new fd is created NOT close-on-exec,
	 223  		// which is exactly what we want.
	 224  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(fd[i]), uintptr(i), 0)
	 225  		if err1 != 0 {
	 226  			goto childerror
	 227  		}
	 228  	}
	 229  
	 230  	// By convention, we don't close-on-exec the fds we are
	 231  	// started with, so if len(fd) < 3, close 0, 1, 2 as needed.
	 232  	// Programs that know they inherit fds >= 3 will need
	 233  	// to set them close-on-exec.
	 234  	for i = len(fd); i < 3; i++ {
	 235  		rawSyscall(abi.FuncPCABI0(libc_close_trampoline), uintptr(i), 0, 0)
	 236  	}
	 237  
	 238  	// Detach fd 0 from tty
	 239  	if sys.Noctty {
	 240  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), 0, uintptr(TIOCNOTTY), 0)
	 241  		if err1 != 0 {
	 242  			goto childerror
	 243  		}
	 244  	}
	 245  
	 246  	// Set the controlling TTY to Ctty
	 247  	if sys.Setctty {
	 248  		_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0)
	 249  		if err1 != 0 {
	 250  			goto childerror
	 251  		}
	 252  	}
	 253  
	 254  	// Time to exec.
	 255  	_, _, err1 = rawSyscall(abi.FuncPCABI0(libc_execve_trampoline),
	 256  		uintptr(unsafe.Pointer(argv0)),
	 257  		uintptr(unsafe.Pointer(&argv[0])),
	 258  		uintptr(unsafe.Pointer(&envv[0])))
	 259  
	 260  childerror:
	 261  	// send error code on pipe
	 262  	rawSyscall(abi.FuncPCABI0(libc_write_trampoline), uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1))
	 263  	for {
	 264  		rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), 253, 0, 0)
	 265  	}
	 266  }
	 267  

View as plain text