github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/syscall/exec_libc2.go (about) 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 // +build darwin openbsd,!mips64 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 pgrp := sys.Pgid 121 if pgrp == 0 { 122 r1, _, err1 = rawSyscall(abi.FuncPCABI0(libc_getpid_trampoline), 0, 0, 0) 123 if err1 != 0 { 124 goto childerror 125 } 126 127 pgrp = int(r1) 128 } 129 130 // Place process group in foreground. 131 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp))) 132 if err1 != 0 { 133 goto childerror 134 } 135 } 136 137 // Restore the signal mask. We do this after TIOCSPGRP to avoid 138 // having the kernel send a SIGTTOU signal to the process group. 139 runtime_AfterForkInChild() 140 141 // Chroot 142 if chroot != nil { 143 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_chroot_trampoline), uintptr(unsafe.Pointer(chroot)), 0, 0) 144 if err1 != 0 { 145 goto childerror 146 } 147 } 148 149 // User and groups 150 if cred := sys.Credential; cred != nil { 151 ngroups := uintptr(len(cred.Groups)) 152 groups := uintptr(0) 153 if ngroups > 0 { 154 groups = uintptr(unsafe.Pointer(&cred.Groups[0])) 155 } 156 if !cred.NoSetGroups { 157 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setgroups_trampoline), ngroups, groups, 0) 158 if err1 != 0 { 159 goto childerror 160 } 161 } 162 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setgid_trampoline), uintptr(cred.Gid), 0, 0) 163 if err1 != 0 { 164 goto childerror 165 } 166 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_setuid_trampoline), uintptr(cred.Uid), 0, 0) 167 if err1 != 0 { 168 goto childerror 169 } 170 } 171 172 // Chdir 173 if dir != nil { 174 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_chdir_trampoline), uintptr(unsafe.Pointer(dir)), 0, 0) 175 if err1 != 0 { 176 goto childerror 177 } 178 } 179 180 // Pass 1: look for fd[i] < i and move those up above len(fd) 181 // so that pass 2 won't stomp on an fd it needs later. 182 if pipe < nextfd { 183 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(pipe), uintptr(nextfd), 0) 184 if err1 != 0 { 185 goto childerror 186 } 187 rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC) 188 pipe = nextfd 189 nextfd++ 190 } 191 for i = 0; i < len(fd); i++ { 192 if fd[i] >= 0 && fd[i] < int(i) { 193 if nextfd == pipe { // don't stomp on pipe 194 nextfd++ 195 } 196 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(fd[i]), uintptr(nextfd), 0) 197 if err1 != 0 { 198 goto childerror 199 } 200 rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(nextfd), F_SETFD, FD_CLOEXEC) 201 fd[i] = nextfd 202 nextfd++ 203 } 204 } 205 206 // Pass 2: dup fd[i] down onto i. 207 for i = 0; i < len(fd); i++ { 208 if fd[i] == -1 { 209 rawSyscall(abi.FuncPCABI0(libc_close_trampoline), uintptr(i), 0, 0) 210 continue 211 } 212 if fd[i] == int(i) { 213 // dup2(i, i) won't clear close-on-exec flag on Linux, 214 // probably not elsewhere either. 215 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_fcntl_trampoline), uintptr(fd[i]), F_SETFD, 0) 216 if err1 != 0 { 217 goto childerror 218 } 219 continue 220 } 221 // The new fd is created NOT close-on-exec, 222 // which is exactly what we want. 223 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_dup2_trampoline), uintptr(fd[i]), uintptr(i), 0) 224 if err1 != 0 { 225 goto childerror 226 } 227 } 228 229 // By convention, we don't close-on-exec the fds we are 230 // started with, so if len(fd) < 3, close 0, 1, 2 as needed. 231 // Programs that know they inherit fds >= 3 will need 232 // to set them close-on-exec. 233 for i = len(fd); i < 3; i++ { 234 rawSyscall(abi.FuncPCABI0(libc_close_trampoline), uintptr(i), 0, 0) 235 } 236 237 // Detach fd 0 from tty 238 if sys.Noctty { 239 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), 0, uintptr(TIOCNOTTY), 0) 240 if err1 != 0 { 241 goto childerror 242 } 243 } 244 245 // Set the controlling TTY to Ctty 246 if sys.Setctty { 247 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_ioctl_trampoline), uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0) 248 if err1 != 0 { 249 goto childerror 250 } 251 } 252 253 // Time to exec. 254 _, _, err1 = rawSyscall(abi.FuncPCABI0(libc_execve_trampoline), 255 uintptr(unsafe.Pointer(argv0)), 256 uintptr(unsafe.Pointer(&argv[0])), 257 uintptr(unsafe.Pointer(&envv[0]))) 258 259 childerror: 260 // send error code on pipe 261 rawSyscall(abi.FuncPCABI0(libc_write_trampoline), uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) 262 for { 263 rawSyscall(abi.FuncPCABI0(libc_exit_trampoline), 253, 0, 0) 264 } 265 }