Skip to content

Commit 9f9c962

Browse files
Merge pull request #1698 from cloudfoundry-incubator/exec-fifo-race
Avoid race when opening exec fifo
2 parents ab4a819 + 5c0af14 commit 9f9c962

File tree

1 file changed

+61
-9
lines changed

1 file changed

+61
-9
lines changed

libcontainer/container_linux.go

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package libcontainer
55
import (
66
"bytes"
77
"encoding/json"
8+
"errors"
89
"fmt"
910
"io"
1011
"io/ioutil"
@@ -267,20 +268,71 @@ func (c *linuxContainer) Exec() error {
267268

268269
func (c *linuxContainer) exec() error {
269270
path := filepath.Join(c.root, execFifoFilename)
270-
f, err := os.OpenFile(path, os.O_RDONLY, 0)
271-
if err != nil {
272-
return newSystemErrorWithCause(err, "open exec fifo for reading")
271+
272+
fifoOpen := make(chan struct{})
273+
select {
274+
case <-awaitProcessExit(c.initProcess.pid(), fifoOpen):
275+
return errors.New("container process is already dead")
276+
case result := <-awaitFifoOpen(path):
277+
close(fifoOpen)
278+
if result.err != nil {
279+
return result.err
280+
}
281+
f := result.file
282+
defer f.Close()
283+
if err := readFromExecFifo(f); err != nil {
284+
return err
285+
}
286+
return os.Remove(path)
273287
}
274-
defer f.Close()
275-
data, err := ioutil.ReadAll(f)
288+
}
289+
290+
func readFromExecFifo(execFifo io.Reader) error {
291+
data, err := ioutil.ReadAll(execFifo)
276292
if err != nil {
277293
return err
278294
}
279-
if len(data) > 0 {
280-
os.Remove(path)
281-
return nil
295+
if len(data) <= 0 {
296+
return fmt.Errorf("cannot start an already running container")
282297
}
283-
return fmt.Errorf("cannot start an already running container")
298+
return nil
299+
}
300+
301+
func awaitProcessExit(pid int, exit <-chan struct{}) <-chan struct{} {
302+
isDead := make(chan struct{})
303+
go func() {
304+
for {
305+
select {
306+
case <-exit:
307+
return
308+
case <-time.After(time.Millisecond * 100):
309+
stat, err := system.Stat(pid)
310+
if err != nil || stat.State == system.Zombie {
311+
close(isDead)
312+
return
313+
}
314+
}
315+
}
316+
}()
317+
return isDead
318+
}
319+
320+
func awaitFifoOpen(path string) <-chan openResult {
321+
fifoOpened := make(chan openResult)
322+
go func() {
323+
f, err := os.OpenFile(path, os.O_RDONLY, 0)
324+
if err != nil {
325+
fifoOpened <- openResult{err: newSystemErrorWithCause(err, "open exec fifo for reading")}
326+
return
327+
}
328+
fifoOpened <- openResult{file: f}
329+
}()
330+
return fifoOpened
331+
}
332+
333+
type openResult struct {
334+
file *os.File
335+
err error
284336
}
285337

286338
func (c *linuxContainer) start(process *Process, isInit bool) error {

0 commit comments

Comments
 (0)