libcontainer/configs: make hooks run safer

It's possible that `cmd.Process` is still nil when we reach timeout.
Start creates `Process` field synchronously, and there is no way to such
race.

Signed-off-by: Alexander Morozov <lk4d4math@gmail.com>
This commit is contained in:
Alexander Morozov 2016-08-08 10:14:11 -07:00
parent 6c7e43594e
commit 7679c80be5
1 changed files with 24 additions and 15 deletions

View File

@ -300,29 +300,38 @@ func (c Command) Run(s HookState) error {
if err != nil { if err != nil {
return err return err
} }
var stdout, stderr bytes.Buffer
cmd := exec.Cmd{ cmd := exec.Cmd{
Path: c.Path, Path: c.Path,
Args: c.Args, Args: c.Args,
Env: c.Env, Env: c.Env,
Stdin: bytes.NewReader(b), Stdin: bytes.NewReader(b),
Stdout: &stdout,
Stderr: &stderr,
}
if err := cmd.Start(); err != nil {
return err
} }
errC := make(chan error, 1) errC := make(chan error, 1)
go func() { go func() {
out, err := cmd.CombinedOutput() err := cmd.Wait()
if err != nil { if err != nil {
err = fmt.Errorf("%s: %s", err, out) err = fmt.Errorf("error running hook: %v, stdout: %s, stderr: %s", err, stdout.String(), stderr.String())
} }
errC <- err errC <- err
}() }()
var timerCh <-chan time.Time
if c.Timeout != nil { if c.Timeout != nil {
timer := time.NewTimer(*c.Timeout)
defer timer.Stop()
timerCh = timer.C
}
select { select {
case err := <-errC: case err := <-errC:
return err return err
case <-time.After(*c.Timeout): case <-timerCh:
cmd.Process.Kill() cmd.Process.Kill()
cmd.Wait() cmd.Wait()
return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds()) return fmt.Errorf("hook ran past specified timeout of %.1fs", c.Timeout.Seconds())
} }
} }
return <-errC
}