@@ -12,53 +12,7 @@ import (
12
12
"unsafe"
13
13
)
14
14
15
- // Lock synchronizing creation of new file descriptors with fork.
16
- //
17
- // We want the child in a fork/exec sequence to inherit only the
18
- // file descriptors we intend. To do that, we mark all file
19
- // descriptors close-on-exec and then, in the child, explicitly
20
- // unmark the ones we want the exec'ed program to keep.
21
- // Unix doesn't make this easy: there is, in general, no way to
22
- // allocate a new file descriptor close-on-exec. Instead you
23
- // have to allocate the descriptor and then mark it close-on-exec.
24
- // If a fork happens between those two events, the child's exec
25
- // will inherit an unwanted file descriptor.
26
- //
27
- // This lock solves that race: the create new fd/mark close-on-exec
28
- // operation is done holding ForkLock for reading, and the fork itself
29
- // is done holding ForkLock for writing. At least, that's the idea.
30
- // There are some complications.
31
- //
32
- // Some system calls that create new file descriptors can block
33
- // for arbitrarily long times: open on a hung NFS server or named
34
- // pipe, accept on a socket, and so on. We can't reasonably grab
35
- // the lock across those operations.
36
- //
37
- // It is worse to inherit some file descriptors than others.
38
- // If a non-malicious child accidentally inherits an open ordinary file,
39
- // that's not a big deal. On the other hand, if a long-lived child
40
- // accidentally inherits the write end of a pipe, then the reader
41
- // of that pipe will not see EOF until that child exits, potentially
42
- // causing the parent program to hang. This is a common problem
43
- // in threaded C programs that use popen.
44
- //
45
- // Luckily, the file descriptors that are most important not to
46
- // inherit are not the ones that can take an arbitrarily long time
47
- // to create: pipe returns instantly, and the net package uses
48
- // non-blocking I/O to accept on a listening socket.
49
- // The rules for which file descriptor-creating operations use the
50
- // ForkLock are as follows:
51
- //
52
- // 1) Pipe. Does not block. Use the ForkLock.
53
- // 2) Socket. Does not block. Use the ForkLock.
54
- // 3) Accept. If using non-blocking mode, use the ForkLock.
55
- // Otherwise, live with the race.
56
- // 4) Open. Can block. Use O_CLOEXEC if available (Linux).
57
- // Otherwise, live with the race.
58
- // 5) Dup. Does not block. Use the ForkLock.
59
- // On Linux, could use fcntl F_DUPFD_CLOEXEC
60
- // instead of the ForkLock, but only for dup(fd, -1).
61
-
15
+ // ForkLock is not used on plan9.
62
16
var ForkLock sync.RWMutex
63
17
64
18
// gstringb reads a non-empty string from b, prefixed with a 16-bit length in little-endian order.
@@ -151,35 +105,6 @@ func readdirnames(dirfd int) (names []string, err error) {
151
105
return
152
106
}
153
107
154
- // readdupdevice returns a list of currently opened fds (excluding stdin, stdout, stderr) from the dup device #d.
155
- // ForkLock should be write locked before calling, so that no new fds would be created while the fd list is being read.
156
- func readdupdevice () (fds []int , err error ) {
157
- dupdevfd , err := Open ("#d" , O_RDONLY )
158
- if err != nil {
159
- return
160
- }
161
- defer Close (dupdevfd )
162
-
163
- names , err := readdirnames (dupdevfd )
164
- if err != nil {
165
- return
166
- }
167
-
168
- fds = make ([]int , 0 , len (names )/ 2 )
169
- for _ , name := range names {
170
- if n := len (name ); n > 3 && name [n - 3 :n ] == "ctl" {
171
- continue
172
- }
173
- fd := int (atoi ([]byte (name )))
174
- switch fd {
175
- case 0 , 1 , 2 , dupdevfd :
176
- continue
177
- }
178
- fds = append (fds , fd )
179
- }
180
- return
181
- }
182
-
183
108
// name of the directory containing names and control files for all open file descriptors
184
109
var dupdev , _ = BytePtrFromString ("#d" )
185
110
@@ -492,9 +417,6 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
492
417
}
493
418
}
494
419
495
- // Acquire the fork lock to prevent other threads from creating new fds before we fork.
496
- ForkLock .Lock ()
497
-
498
420
// Allocate child status pipe close on exec.
499
421
e := cexecPipe (p [:])
500
422
@@ -510,10 +432,8 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
510
432
Close (p [0 ])
511
433
Close (p [1 ])
512
434
}
513
- ForkLock .Unlock ()
514
435
return 0 , err
515
436
}
516
- ForkLock .Unlock ()
517
437
518
438
// Read child error status from pipe.
519
439
Close (p [1 ])
0 commit comments