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,