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