github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/syscall/exec_bsd.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 dragonfly || freebsd || netbsd || (openbsd && mips64) 6 // +build dragonfly freebsd netbsd openbsd,mips64 7 8 package syscall 9 10 import ( 11 "unsafe" 12 ) 13 14 type SysProcAttr struct { 15 Chroot string // Chroot. 16 Credential *Credential // Credential. 17 Ptrace bool // Enable tracing. 18 Setsid bool // Create session. 19 // Setpgid sets the process group ID of the child to Pgid, 20 // or, if Pgid == 0, to the new child's process ID. 21 Setpgid bool 22 // Setctty sets the controlling terminal of the child to 23 // file descriptor Ctty. Ctty must be a descriptor number 24 // in the child process: an index into ProcAttr.Files. 25 // This is only meaningful if Setsid is true. 26 Setctty bool 27 Noctty bool // Detach fd 0 from controlling terminal 28 Ctty int // Controlling TTY fd 29 // Foreground places the child process group in the foreground. 30 // This implies Setpgid. The Ctty field must be set to 31 // the descriptor of the controlling TTY. 32 // Unlike Setctty, in this case Ctty must be a descriptor 33 // number in the parent process. 34 Foreground bool 35 Pgid int // Child's process group ID if Setpgid. 36 } 37 38 // Implemented in runtime package. 39 func runtime_BeforeFork() 40 func runtime_AfterFork() 41 func runtime_AfterForkInChild() 42 43 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. 44 // If a dup or exec fails, write the errno error to pipe. 45 // (Pipe is close-on-exec so if exec succeeds, it will be closed.) 46 // In the child, this function must not acquire any locks, because 47 // they might have been locked at the time of the fork. This means 48 // no rescheduling, no malloc calls, and no new stack segments. 49 // For the same reason compiler does not race instrument it. 50 // The calls to RawSyscall are okay because they are assembly 51 // functions that do not grow the stack. 52 //go:norace 53 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { 54 // Declare all variables at top in case any 55 // declarations require heap allocation (e.g., err1). 56 var ( 57 r1 uintptr 58 err1 Errno 59 nextfd int 60 i int 61 ) 62 63 // guard against side effects of shuffling fds below. 64 // Make sure that nextfd is beyond any currently open files so 65 // that we can't run the risk of overwriting any of them. 66 fd := make([]int, len(attr.Files)) 67 nextfd = len(attr.Files) 68 for i, ufd := range attr.Files { 69 if nextfd < int(ufd) { 70 nextfd = int(ufd) 71 } 72 fd[i] = int(ufd) 73 } 74 nextfd++ 75 76 // About to call fork. 77 // No more allocation or calls of non-assembly functions. 78 runtime_BeforeFork() 79 r1, _, err1 = RawSyscall(SYS_FORK, 0, 0, 0) 80 if err1 != 0 { 81 runtime_AfterFork() 82 return 0, err1 83 } 84 85 if r1 != 0 { 86 // parent; return PID 87 runtime_AfterFork() 88 return int(r1), 0 89 } 90 91 // Fork succeeded, now in child. 92 93 // Enable tracing if requested. 94 if sys.Ptrace { 95 _, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0) 96 if err1 != 0 { 97 goto childerror 98 } 99 } 100 101 // Session ID 102 if sys.Setsid { 103 _, _, err1 = RawSyscall(SYS_SETSID, 0, 0, 0) 104 if err1 != 0 { 105 goto childerror 106 } 107 } 108 109 // Set process group 110 if sys.Setpgid || sys.Foreground { 111 // Place child in process group. 112 _, _, err1 = RawSyscall(SYS_SETPGID, 0, uintptr(sys.Pgid), 0) 113 if err1 != 0 { 114 goto childerror 115 } 116 } 117 118 if sys.Foreground { 119 // This should really be pid_t, however _C_int (aka int32) is 120 // generally equivalent. 121 pgrp := _C_int(sys.Pgid) 122 if pgrp == 0 { 123 r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0) 124 if err1 != 0 { 125 goto childerror 126 } 127 128 pgrp = _C_int(r1) 129 } 130 131 // Place process group in foreground. 132 _, _, err1 = RawSyscall(SYS_IOCTL, 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(SYS_CHROOT, 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(SYS_SETGROUPS, ngroups, groups, 0) 159 if err1 != 0 { 160 goto childerror 161 } 162 } 163 _, _, err1 = RawSyscall(SYS_SETGID, uintptr(cred.Gid), 0, 0) 164 if err1 != 0 { 165 goto childerror 166 } 167 _, _, err1 = RawSyscall(SYS_SETUID, uintptr(cred.Uid), 0, 0) 168 if err1 != 0 { 169 goto childerror 170 } 171 } 172 173 // Chdir 174 if dir != nil { 175 _, _, err1 = RawSyscall(SYS_CHDIR, 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(SYS_DUP2, uintptr(pipe), uintptr(nextfd), 0) 185 if err1 != 0 { 186 goto childerror 187 } 188 RawSyscall(SYS_FCNTL, 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(SYS_DUP2, uintptr(fd[i]), uintptr(nextfd), 0) 198 if err1 != 0 { 199 goto childerror 200 } 201 RawSyscall(SYS_FCNTL, 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(SYS_CLOSE, 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(SYS_FCNTL, 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(SYS_DUP2, 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(SYS_CLOSE, uintptr(i), 0, 0) 236 } 237 238 // Detach fd 0 from tty 239 if sys.Noctty { 240 _, _, err1 = RawSyscall(SYS_IOCTL, 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(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0) 249 if err1 != 0 { 250 goto childerror 251 } 252 } 253 254 // Time to exec. 255 _, _, err1 = RawSyscall(SYS_EXECVE, 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(SYS_WRITE, uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) 263 for { 264 RawSyscall(SYS_EXIT, 253, 0, 0) 265 } 266 }