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