github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/syscall/exec_libc.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 aix || solaris 6 // +build aix solaris 7 8 // This file handles forkAndExecInChild function for OS using libc syscall like AIX or Solaris. 9 10 package syscall 11 12 import ( 13 "unsafe" 14 ) 15 16 type SysProcAttr struct { 17 Chroot string // Chroot. 18 Credential *Credential // Credential. 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 func chdir(path uintptr) (err Errno) 45 func chroot1(path uintptr) (err Errno) 46 func close(fd uintptr) (err Errno) 47 func dup2child(old uintptr, new uintptr) (val uintptr, err Errno) 48 func execve(path uintptr, argv uintptr, envp uintptr) (err Errno) 49 func exit(code uintptr) 50 func fcntl1(fd uintptr, cmd uintptr, arg uintptr) (val uintptr, err Errno) 51 func forkx(flags uintptr) (pid uintptr, err Errno) 52 func getpid() (pid uintptr, err Errno) 53 func ioctl(fd uintptr, req uintptr, arg uintptr) (err Errno) 54 func setgid(gid uintptr) (err Errno) 55 func setgroups1(ngid uintptr, gid uintptr) (err Errno) 56 func setsid() (pid uintptr, err Errno) 57 func setuid(uid uintptr) (err Errno) 58 func setpgid(pid uintptr, pgid uintptr) (err Errno) 59 func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno) 60 61 // syscall defines this global on our behalf to avoid a build dependency on other platforms 62 func init() { 63 execveLibc = execve 64 } 65 66 // Fork, dup fd onto 0..len(fd), and exec(argv0, argvv, envv) in child. 67 // If a dup or exec fails, write the errno error to pipe. 68 // (Pipe is close-on-exec so if exec succeeds, it will be closed.) 69 // In the child, this function must not acquire any locks, because 70 // they might have been locked at the time of the fork. This means 71 // no rescheduling, no malloc calls, and no new stack segments. 72 // 73 // We call hand-crafted syscalls, implemented in 74 // ../runtime/syscall_solaris.go, rather than generated libc wrappers 75 // because we need to avoid lazy-loading the functions (might malloc, 76 // split the stack, or acquire mutexes). We can't call RawSyscall 77 // because it's not safe even for BSD-subsystem calls. 78 //go:norace 79 func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err Errno) { 80 // Declare all variables at top in case any 81 // declarations require heap allocation (e.g., err1). 82 var ( 83 r1 uintptr 84 err1 Errno 85 nextfd int 86 i int 87 ) 88 89 // guard against side effects of shuffling fds below. 90 // Make sure that nextfd is beyond any currently open files so 91 // that we can't run the risk of overwriting any of them. 92 fd := make([]int, len(attr.Files)) 93 nextfd = len(attr.Files) 94 for i, ufd := range attr.Files { 95 if nextfd < int(ufd) { 96 nextfd = int(ufd) 97 } 98 fd[i] = int(ufd) 99 } 100 nextfd++ 101 102 // About to call fork. 103 // No more allocation or calls of non-assembly functions. 104 runtime_BeforeFork() 105 r1, err1 = forkx(0x1) // FORK_NOSIGCHLD 106 if err1 != 0 { 107 runtime_AfterFork() 108 return 0, err1 109 } 110 111 if r1 != 0 { 112 // parent; return PID 113 runtime_AfterFork() 114 return int(r1), 0 115 } 116 117 // Fork succeeded, now in child. 118 119 // Session ID 120 if sys.Setsid { 121 _, err1 = setsid() 122 if err1 != 0 { 123 goto childerror 124 } 125 } 126 127 // Set process group 128 if sys.Setpgid || sys.Foreground { 129 // Place child in process group. 130 err1 = setpgid(0, uintptr(sys.Pgid)) 131 if err1 != 0 { 132 goto childerror 133 } 134 } 135 136 if sys.Foreground { 137 pgrp := _Pid_t(sys.Pgid) 138 if pgrp == 0 { 139 r1, err1 = getpid() 140 if err1 != 0 { 141 goto childerror 142 } 143 144 pgrp = _Pid_t(r1) 145 } 146 147 // Place process group in foreground. 148 err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp))) 149 if err1 != 0 { 150 goto childerror 151 } 152 } 153 154 // Restore the signal mask. We do this after TIOCSPGRP to avoid 155 // having the kernel send a SIGTTOU signal to the process group. 156 runtime_AfterForkInChild() 157 158 // Chroot 159 if chroot != nil { 160 err1 = chroot1(uintptr(unsafe.Pointer(chroot))) 161 if err1 != 0 { 162 goto childerror 163 } 164 } 165 166 // User and groups 167 if cred := sys.Credential; cred != nil { 168 ngroups := uintptr(len(cred.Groups)) 169 groups := uintptr(0) 170 if ngroups > 0 { 171 groups = uintptr(unsafe.Pointer(&cred.Groups[0])) 172 } 173 if !cred.NoSetGroups { 174 err1 = setgroups1(ngroups, groups) 175 if err1 != 0 { 176 goto childerror 177 } 178 } 179 err1 = setgid(uintptr(cred.Gid)) 180 if err1 != 0 { 181 goto childerror 182 } 183 err1 = setuid(uintptr(cred.Uid)) 184 if err1 != 0 { 185 goto childerror 186 } 187 } 188 189 // Chdir 190 if dir != nil { 191 err1 = chdir(uintptr(unsafe.Pointer(dir))) 192 if err1 != 0 { 193 goto childerror 194 } 195 } 196 197 // Pass 1: look for fd[i] < i and move those up above len(fd) 198 // so that pass 2 won't stomp on an fd it needs later. 199 if pipe < nextfd { 200 _, err1 = dup2child(uintptr(pipe), uintptr(nextfd)) 201 if err1 != 0 { 202 goto childerror 203 } 204 fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC) 205 pipe = nextfd 206 nextfd++ 207 } 208 for i = 0; i < len(fd); i++ { 209 if fd[i] >= 0 && fd[i] < int(i) { 210 if nextfd == pipe { // don't stomp on pipe 211 nextfd++ 212 } 213 _, err1 = dup2child(uintptr(fd[i]), uintptr(nextfd)) 214 if err1 != 0 { 215 goto childerror 216 } 217 _, err1 = fcntl1(uintptr(nextfd), F_SETFD, FD_CLOEXEC) 218 if err1 != 0 { 219 goto childerror 220 } 221 fd[i] = nextfd 222 nextfd++ 223 } 224 } 225 226 // Pass 2: dup fd[i] down onto i. 227 for i = 0; i < len(fd); i++ { 228 if fd[i] == -1 { 229 close(uintptr(i)) 230 continue 231 } 232 if fd[i] == int(i) { 233 // dup2(i, i) won't clear close-on-exec flag on Linux, 234 // probably not elsewhere either. 235 _, err1 = fcntl1(uintptr(fd[i]), F_SETFD, 0) 236 if err1 != 0 { 237 goto childerror 238 } 239 continue 240 } 241 // The new fd is created NOT close-on-exec, 242 // which is exactly what we want. 243 _, err1 = dup2child(uintptr(fd[i]), uintptr(i)) 244 if err1 != 0 { 245 goto childerror 246 } 247 } 248 249 // By convention, we don't close-on-exec the fds we are 250 // started with, so if len(fd) < 3, close 0, 1, 2 as needed. 251 // Programs that know they inherit fds >= 3 will need 252 // to set them close-on-exec. 253 for i = len(fd); i < 3; i++ { 254 close(uintptr(i)) 255 } 256 257 // Detach fd 0 from tty 258 if sys.Noctty { 259 err1 = ioctl(0, uintptr(TIOCNOTTY), 0) 260 if err1 != 0 { 261 goto childerror 262 } 263 } 264 265 // Set the controlling TTY to Ctty 266 if sys.Setctty { 267 // On AIX, TIOCSCTTY is undefined 268 if TIOCSCTTY == 0 { 269 err1 = ENOSYS 270 goto childerror 271 } 272 err1 = ioctl(uintptr(sys.Ctty), uintptr(TIOCSCTTY), 0) 273 if err1 != 0 { 274 goto childerror 275 } 276 } 277 278 // Time to exec. 279 err1 = execve( 280 uintptr(unsafe.Pointer(argv0)), 281 uintptr(unsafe.Pointer(&argv[0])), 282 uintptr(unsafe.Pointer(&envv[0]))) 283 284 childerror: 285 // send error code on pipe 286 write1(uintptr(pipe), uintptr(unsafe.Pointer(&err1)), unsafe.Sizeof(err1)) 287 for { 288 exit(253) 289 } 290 }