From 92772bd471ff3ee24486fa0cc2f497d17d35590a Mon Sep 17 00:00:00 2001 From: Kenfe-Mickael Laventure Date: Fri, 1 Sep 2017 09:41:37 -0700 Subject: [PATCH] linux: Ensure all init children are dead when it exits This ensure that when using the host pid, we don't let process alive, preventing Wait() to return until they all die. Signed-off-by: Kenfe-Mickael Laventure --- container_linux_test.go | 76 +++++++++++++++++++++++++++++++++++++++++ linux/shim/service.go | 8 +++++ 2 files changed, 84 insertions(+) diff --git a/container_linux_test.go b/container_linux_test.go index f70fb5bb3..093225884 100644 --- a/container_linux_test.go +++ b/container_linux_test.go @@ -896,3 +896,79 @@ func TestContainerRuntimeOptions(t *testing.T) { t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error()) } } + +func TestContainerKillInitPidHost(t *testing.T) { + client, err := newClient(t, address) + if err != nil { + t.Fatal(err) + } + defer client.Close() + + var ( + image Image + ctx, cancel = testContext() + id = t.Name() + ) + defer cancel() + + image, err = client.GetImage(ctx, testImage) + if err != nil { + t.Error(err) + return + } + + container, err := client.NewContainer(ctx, id, + withNewSnapshot(id, image), + WithNewSpec(withImageConfig(image), + withProcessArgs("sh", "-c", "sleep 42; echo hi"), + WithHostNamespace(specs.PIDNamespace), + ), + ) + if err != nil { + t.Error(err) + return + } + defer container.Delete(ctx, WithSnapshotCleanup) + + stdout := bytes.NewBuffer(nil) + task, err := container.NewTask(ctx, NewIO(bytes.NewBuffer(nil), stdout, bytes.NewBuffer(nil))) + if err != nil { + t.Error(err) + return + } + defer task.Delete(ctx) + + statusC, err := task.Wait(ctx) + if err != nil { + t.Error(err) + return + } + + if err := task.Start(ctx); err != nil { + t.Error(err) + return + } + + if err := task.Kill(ctx, syscall.SIGKILL); err != nil { + t.Error(err) + } + + // Give the shim time to reap the init process and kill the orphans + select { + case <-statusC: + case <-time.After(100 * time.Millisecond): + } + + b, err := exec.Command("ps", "ax").CombinedOutput() + if err != nil { + t.Fatal(err) + } + + if strings.Contains(string(b), "sleep 42") { + t.Fatalf("killing init didn't kill all its children:\n%v", string(b)) + } + + if _, err := task.Delete(ctx, WithProcessKill); err != nil { + t.Error(err) + } +} diff --git a/linux/shim/service.go b/linux/shim/service.go index 874babb9e..fc4d0993e 100644 --- a/linux/shim/service.go +++ b/linux/shim/service.go @@ -393,6 +393,14 @@ func (s *Service) checkProcesses(e runc.Exit) { defer s.mu.Unlock() for _, p := range s.processes { if p.Pid() == e.Pid { + if ip, ok := p.(*initProcess); ok { + // Ensure all children are killed + if err := ip.killAll(s.context); err != nil { + log.G(s.context).WithError(err).WithField("id", ip.ID()). + Error("failed to kill init's children") + } + } + p.SetExited(e.Status) s.events <- &eventsapi.TaskExit{ ContainerID: s.id,