Files
docker-cli/components/engine/pkg/libcontainer/nsinit/exec.go
Alexander Larsson 098ea0f413 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)
Upstream-commit: 5c9b28db1853cccdf7a1037eeaad372d12cd68fa
Component: engine
2014-03-06 14:10:32 +01:00

97 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)
}