github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/syscall/exec_unix.go (about) 1 // Copyright 2009 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 || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris 6 // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris 7 8 // Fork, exec, wait, etc. 9 10 package syscall 11 12 import ( 13 errorspkg "errors" 14 "internal/bytealg" 15 "runtime" 16 "sync" 17 "unsafe" 18 ) 19 20 // Lock synchronizing creation of new file descriptors with fork. 21 // 22 // We want the child in a fork/exec sequence to inherit only the 23 // file descriptors we intend. To do that, we mark all file 24 // descriptors close-on-exec and then, in the child, explicitly 25 // unmark the ones we want the exec'ed program to keep. 26 // Unix doesn't make this easy: there is, in general, no way to 27 // allocate a new file descriptor close-on-exec. Instead you 28 // have to allocate the descriptor and then mark it close-on-exec. 29 // If a fork happens between those two events, the child's exec 30 // will inherit an unwanted file descriptor. 31 // 32 // This lock solves that race: the create new fd/mark close-on-exec 33 // operation is done holding ForkLock for reading, and the fork itself 34 // is done holding ForkLock for writing. At least, that's the idea. 35 // There are some complications. 36 // 37 // Some system calls that create new file descriptors can block 38 // for arbitrarily long times: open on a hung NFS server or named 39 // pipe, accept on a socket, and so on. We can't reasonably grab 40 // the lock across those operations. 41 // 42 // It is worse to inherit some file descriptors than others. 43 // If a non-malicious child accidentally inherits an open ordinary file, 44 // that's not a big deal. On the other hand, if a long-lived child 45 // accidentally inherits the write end of a pipe, then the reader 46 // of that pipe will not see EOF until that child exits, potentially 47 // causing the parent program to hang. This is a common problem 48 // in threaded C programs that use popen. 49 // 50 // Luckily, the file descriptors that are most important not to 51 // inherit are not the ones that can take an arbitrarily long time 52 // to create: pipe returns instantly, and the net package uses 53 // non-blocking I/O to accept on a listening socket. 54 // The rules for which file descriptor-creating operations use the 55 // ForkLock are as follows: 56 // 57 // 1) Pipe. Does not block. Use the ForkLock. 58 // 2) Socket. Does not block. Use the ForkLock. 59 // 3) Accept. If using non-blocking mode, use the ForkLock. 60 // Otherwise, live with the race. 61 // 4) Open. Can block. Use O_CLOEXEC if available (Linux). 62 // Otherwise, live with the race. 63 // 5) Dup. Does not block. Use the ForkLock. 64 // On Linux, could use fcntl F_DUPFD_CLOEXEC 65 // instead of the ForkLock, but only for dup(fd, -1). 66 67 var ForkLock sync.RWMutex 68 69 // StringSlicePtr converts a slice of strings to a slice of pointers 70 // to NUL-terminated byte arrays. If any string contains a NUL byte 71 // this function panics instead of returning an error. 72 // 73 // Deprecated: Use SlicePtrFromStrings instead. 74 func StringSlicePtr(ss []string) []*byte { 75 bb := make([]*byte, len(ss)+1) 76 for i := 0; i < len(ss); i++ { 77 bb[i] = StringBytePtr(ss[i]) 78 } 79 bb[len(ss)] = nil 80 return bb 81 } 82 83 // SlicePtrFromStrings converts a slice of strings to a slice of 84 // pointers to NUL-terminated byte arrays. If any string contains 85 // a NUL byte, it returns (nil, EINVAL). 86 func SlicePtrFromStrings(ss []string) ([]*byte, error) { 87 n := 0 88 for _, s := range ss { 89 if bytealg.IndexByteString(s, 0) != -1 { 90 return nil, EINVAL 91 } 92 n += len(s) + 1 // +1 for NUL 93 } 94 bb := make([]*byte, len(ss)+1) 95 b := make([]byte, n) 96 n = 0 97 for i, s := range ss { 98 bb[i] = &b[n] 99 copy(b[n:], s) 100 n += len(s) + 1 101 } 102 return bb, nil 103 } 104 105 func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) } 106 107 func SetNonblock(fd int, nonblocking bool) (err error) { 108 flag, err := fcntl(fd, F_GETFL, 0) 109 if err != nil { 110 return err 111 } 112 if nonblocking { 113 flag |= O_NONBLOCK 114 } else { 115 flag &^= O_NONBLOCK 116 } 117 _, err = fcntl(fd, F_SETFL, flag) 118 return err 119 } 120 121 // Credential holds user and group identities to be assumed 122 // by a child process started by StartProcess. 123 type Credential struct { 124 Uid uint32 // User ID. 125 Gid uint32 // Group ID. 126 Groups []uint32 // Supplementary group IDs. 127 NoSetGroups bool // If true, don't set supplementary groups 128 } 129 130 // ProcAttr holds attributes that will be applied to a new process started 131 // by StartProcess. 132 type ProcAttr struct { 133 Dir string // Current working directory. 134 Env []string // Environment. 135 Files []uintptr // File descriptors. 136 Sys *SysProcAttr 137 } 138 139 var zeroProcAttr ProcAttr 140 var zeroSysProcAttr SysProcAttr 141 142 func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 143 var p [2]int 144 var n int 145 var err1 Errno 146 var wstatus WaitStatus 147 148 if attr == nil { 149 attr = &zeroProcAttr 150 } 151 sys := attr.Sys 152 if sys == nil { 153 sys = &zeroSysProcAttr 154 } 155 156 // Convert args to C form. 157 argv0p, err := BytePtrFromString(argv0) 158 if err != nil { 159 return 0, err 160 } 161 argvp, err := SlicePtrFromStrings(argv) 162 if err != nil { 163 return 0, err 164 } 165 envvp, err := SlicePtrFromStrings(attr.Env) 166 if err != nil { 167 return 0, err 168 } 169 170 if (runtime.GOOS == "freebsd" || runtime.GOOS == "dragonfly") && len(argv[0]) > len(argv0) { 171 argvp[0] = argv0p 172 } 173 174 var chroot *byte 175 if sys.Chroot != "" { 176 chroot, err = BytePtrFromString(sys.Chroot) 177 if err != nil { 178 return 0, err 179 } 180 } 181 var dir *byte 182 if attr.Dir != "" { 183 dir, err = BytePtrFromString(attr.Dir) 184 if err != nil { 185 return 0, err 186 } 187 } 188 189 // Both Setctty and Foreground use the Ctty field, 190 // but they give it slightly different meanings. 191 if sys.Setctty && sys.Foreground { 192 return 0, errorspkg.New("both Setctty and Foreground set in SysProcAttr") 193 } 194 if sys.Setctty && sys.Ctty >= len(attr.Files) { 195 return 0, errorspkg.New("Setctty set but Ctty not valid in child") 196 } 197 198 // Acquire the fork lock so that no other threads 199 // create new fds that are not yet close-on-exec 200 // before we fork. 201 ForkLock.Lock() 202 203 // Allocate child status pipe close on exec. 204 if err = forkExecPipe(p[:]); err != nil { 205 ForkLock.Unlock() 206 return 0, err 207 } 208 209 // Kick off child. 210 pid, err1 = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1]) 211 if err1 != 0 { 212 Close(p[0]) 213 Close(p[1]) 214 ForkLock.Unlock() 215 return 0, Errno(err1) 216 } 217 ForkLock.Unlock() 218 219 // Read child error status from pipe. 220 Close(p[1]) 221 for { 222 n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1))) 223 if err != EINTR { 224 break 225 } 226 } 227 Close(p[0]) 228 if err != nil || n != 0 { 229 if n == int(unsafe.Sizeof(err1)) { 230 err = Errno(err1) 231 } 232 if err == nil { 233 err = EPIPE 234 } 235 236 // Child failed; wait for it to exit, to make sure 237 // the zombies don't accumulate. 238 _, err1 := Wait4(pid, &wstatus, 0, nil) 239 for err1 == EINTR { 240 _, err1 = Wait4(pid, &wstatus, 0, nil) 241 } 242 return 0, err 243 } 244 245 // Read got EOF, so pipe closed on exec, so exec succeeded. 246 return pid, nil 247 } 248 249 // Combination of fork and exec, careful to be thread safe. 250 func ForkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error) { 251 return forkExec(argv0, argv, attr) 252 } 253 254 // StartProcess wraps ForkExec for package os. 255 func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { 256 pid, err = forkExec(argv0, argv, attr) 257 return pid, 0, err 258 } 259 260 // Implemented in runtime package. 261 func runtime_BeforeExec() 262 func runtime_AfterExec() 263 264 // execveLibc is non-nil on OS using libc syscall, set to execve in exec_libc.go; this 265 // avoids a build dependency for other platforms. 266 var execveLibc func(path uintptr, argv uintptr, envp uintptr) Errno 267 var execveDarwin func(path *byte, argv **byte, envp **byte) error 268 var execveOpenBSD func(path *byte, argv **byte, envp **byte) error 269 270 // Exec invokes the execve(2) system call. 271 func Exec(argv0 string, argv []string, envv []string) (err error) { 272 argv0p, err := BytePtrFromString(argv0) 273 if err != nil { 274 return err 275 } 276 argvp, err := SlicePtrFromStrings(argv) 277 if err != nil { 278 return err 279 } 280 envvp, err := SlicePtrFromStrings(envv) 281 if err != nil { 282 return err 283 } 284 runtime_BeforeExec() 285 286 var err1 error 287 if runtime.GOOS == "solaris" || runtime.GOOS == "illumos" || runtime.GOOS == "aix" { 288 // RawSyscall should never be used on Solaris, illumos, or AIX. 289 err1 = execveLibc( 290 uintptr(unsafe.Pointer(argv0p)), 291 uintptr(unsafe.Pointer(&argvp[0])), 292 uintptr(unsafe.Pointer(&envvp[0]))) 293 } else if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { 294 // Similarly on Darwin. 295 err1 = execveDarwin(argv0p, &argvp[0], &envvp[0]) 296 } else if runtime.GOOS == "openbsd" && (runtime.GOARCH == "386" || runtime.GOARCH == "amd64" || runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 297 // Similarly on OpenBSD. 298 err1 = execveOpenBSD(argv0p, &argvp[0], &envvp[0]) 299 } else { 300 _, _, err1 = RawSyscall(SYS_EXECVE, 301 uintptr(unsafe.Pointer(argv0p)), 302 uintptr(unsafe.Pointer(&argvp[0])), 303 uintptr(unsafe.Pointer(&envvp[0]))) 304 } 305 runtime_AfterExec() 306 return err1 307 }