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