blob: 890bfdc2272caef6167188b084f90b729fc3c49c [file] [log] [blame]
Colin Cross7bb052a2015-02-03 12:59:37 -08001// 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
9package syscall
10
11import (
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
64var 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.
69func 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).
81func 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
94func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
95
96func 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.
112type 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.
120type ProcAttr struct {
121 Dir string // Current working directory.
122 Env []string // Environment.
123 Files []uintptr // File descriptors.
124 Sys *SysProcAttr
125}
126
127var zeroProcAttr ProcAttr
128var zeroSysProcAttr SysProcAttr
129
130func 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
222error:
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.
232func 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.
237func 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.
243func 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}