pkg/libcontainer/nsinit/exec.go
Alexander Larsson 0caa2d3992 libcontainer: Don't use UsetCloseOnExec, it is racy
We can't keep file descriptors without close-on-exec except with
syscall.ForkLock held, as otherwise they could leak by accident into
other children from forks in other threads.

Instead we just use Cmd.ExtraFiles which handles all this for us.

This fixes https://github.com/dotcloud/docker/issues/4493

Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson)
2014-03-06 14:10:32 +01:00

96 lines
2.4 KiB
Go

// +build linux
package nsinit
import (
"github.com/dotcloud/docker/pkg/libcontainer"
"github.com/dotcloud/docker/pkg/libcontainer/network"
"github.com/dotcloud/docker/pkg/system"
"os"
"os/exec"
"syscall"
)
// Exec performes setup outside of a namespace so that a container can be
// executed. Exec is a high level function for working with container namespaces.
func (ns *linuxNs) Exec(container *libcontainer.Container, term Terminal, args []string) (int, error) {
var (
master *os.File
console string
err error
)
// create a pipe so that we can syncronize with the namespaced process and
// pass the veth name to the child
syncPipe, err := NewSyncPipe()
if err != nil {
return -1, err
}
if container.Tty {
master, console, err = system.CreateMasterAndConsole()
if err != nil {
return -1, err
}
term.SetMaster(master)
}
command := ns.commandFactory.Create(container, console, syncPipe.child, args)
if err := term.Attach(command); err != nil {
return -1, err
}
defer term.Close()
if err := command.Start(); err != nil {
return -1, err
}
if err := ns.stateWriter.WritePid(command.Process.Pid); err != nil {
command.Process.Kill()
return -1, err
}
defer ns.stateWriter.DeletePid()
// Do this before syncing with child so that no children
// can escape the cgroup
if err := ns.SetupCgroups(container, command.Process.Pid); err != nil {
command.Process.Kill()
return -1, err
}
if err := ns.InitializeNetworking(container, command.Process.Pid, syncPipe); err != nil {
command.Process.Kill()
return -1, err
}
// Sync with child
syncPipe.Close()
if err := command.Wait(); err != nil {
if _, ok := err.(*exec.ExitError); !ok {
return -1, err
}
}
return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil
}
func (ns *linuxNs) SetupCgroups(container *libcontainer.Container, nspid int) error {
if container.Cgroups != nil {
if err := container.Cgroups.Apply(nspid); err != nil {
return err
}
}
return nil
}
func (ns *linuxNs) InitializeNetworking(container *libcontainer.Container, nspid int, pipe *SyncPipe) error {
context := libcontainer.Context{}
for _, config := range container.Networks {
strategy, err := network.GetStrategy(config.Type)
if err != nil {
return err
}
if err := strategy.Create(config, nspid, context); err != nil {
return err
}
}
return pipe.SendToChild(context)
}