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 7package syscall 8 9import ( 10 "internal/abi" 11 "runtime" 12 "unsafe" 13) 14 15type 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. 40func runtime_BeforeFork() 41func runtime_AfterFork() 42func 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 55func 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 285childerror: 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. 294func forkAndExecFailureCleanup(attr *ProcAttr, sys *SysProcAttr) { 295 // Nothing to do. 296} 297