From 1bd146ed82f771395f991851f7d896d9ae778f3c Mon Sep 17 00:00:00 2001 From: Dan Walsh Date: Wed, 7 Jan 2015 17:19:36 -0500 Subject: [PATCH] This patch adds a test for the shared HOST Pid namespace It also kills all processes in a cgroup if you are not using the pid namespace If we stop using the PID namespace, and more then one process is running when the pid 1 exits, docker will hang since the cgroups do not disappear. This code will kill all remaining processes Add Tests for handing of Pid Namespaces Docker-DCO-1.1-Signed-off-by: Dan Walsh (github: rhatdan) --- integration/exec_test.go | 35 +++++++++++++++++++++++++++++++++-- namespaces/exec.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/integration/exec_test.go b/integration/exec_test.go index f0728c581..fb1d1d7a1 100644 --- a/integration/exec_test.go +++ b/integration/exec_test.go @@ -67,7 +67,7 @@ func TestIPCPrivate(t *testing.T) { } if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l { - t.Fatalf("ipc link should be private to the conatiner but equals host %q %q", actual, l) + t.Fatalf("ipc link should be private to the container but equals host %q %q", actual, l) } } @@ -152,7 +152,7 @@ func TestIPCBadPath(t *testing.T) { _, _, err = runContainer(config, "", "true") if err == nil { - t.Fatal("container succeded with bad ipc path") + t.Fatal("container succeeded with bad ipc path") } } @@ -176,3 +176,34 @@ func TestRlimit(t *testing.T) { t.Fatalf("expected rlimit to be 1024, got %s", limit) } } + +func TestPIDNSPrivate(t *testing.T) { + if testing.Short() { + return + } + + rootfs, err := newRootFs() + if err != nil { + t.Fatal(err) + } + defer remove(rootfs) + + l, err := os.Readlink("/proc/1/ns/pid") + if err != nil { + t.Fatal(err) + } + + config := newTemplateConfig(rootfs) + buffers, exitCode, err := runContainer(config, "", "readlink", "/proc/self/ns/pid") + if err != nil { + t.Fatal(err) + } + + if exitCode != 0 { + t.Fatalf("exit code not 0. code %d stderr %q", exitCode, buffers.Stderr) + } + + if actual := strings.Trim(buffers.Stdout.String(), "\n"); actual == l { + t.Fatalf("pid link should be private to the container but equals host %q %q", actual, l) + } +} diff --git a/namespaces/exec.go b/namespaces/exec.go index b7873edd0..58970f9f7 100644 --- a/namespaces/exec.go +++ b/namespaces/exec.go @@ -110,9 +110,40 @@ func Exec(container *libcontainer.Config, stdin io.Reader, stdout, stderr io.Wri return -1, err } } + if !container.Namespaces.Contains(libcontainer.NEWPID) { + killAllPids(container) + } return command.ProcessState.Sys().(syscall.WaitStatus).ExitStatus(), nil } +func killAllPids(container *libcontainer.Config) { + var ( + pids []int + err error + ) + freeze := fs.Freeze + getPids := fs.GetPids + if systemd.UseSystemd() { + freeze = systemd.Freeze + getPids = systemd.GetPids + } + + freeze(container.Cgroups, cgroups.Frozen) + if pids, err = getPids(container.Cgroups); err == nil { + for _, pid := range pids { + if p, err := os.FindProcess(pid); err == nil { + p.Kill() + } + } + } + freeze(container.Cgroups, cgroups.Thawed) + for _, pid := range pids { + if p, err := os.FindProcess(pid); err == nil { + p.Wait() + } + } +} + // DefaultCreateCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces // defined on the container's configuration and use the current binary as the init with the // args provided