Skip to content

Commit 92772bd

Browse files
committed
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 <mickael.laventure@gmail.com>
1 parent 9d251cb commit 92772bd

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

container_linux_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,3 +896,79 @@ func TestContainerRuntimeOptions(t *testing.T) {
896896
t.Errorf("task creation should have failed because of lack of executable. Instead failed with: %v", err.Error())
897897
}
898898
}
899+
900+
func TestContainerKillInitPidHost(t *testing.T) {
901+
client, err := newClient(t, address)
902+
if err != nil {
903+
t.Fatal(err)
904+
}
905+
defer client.Close()
906+
907+
var (
908+
image Image
909+
ctx, cancel = testContext()
910+
id = t.Name()
911+
)
912+
defer cancel()
913+
914+
image, err = client.GetImage(ctx, testImage)
915+
if err != nil {
916+
t.Error(err)
917+
return
918+
}
919+
920+
container, err := client.NewContainer(ctx, id,
921+
withNewSnapshot(id, image),
922+
WithNewSpec(withImageConfig(image),
923+
withProcessArgs("sh", "-c", "sleep 42; echo hi"),
924+
WithHostNamespace(specs.PIDNamespace),
925+
),
926+
)
927+
if err != nil {
928+
t.Error(err)
929+
return
930+
}
931+
defer container.Delete(ctx, WithSnapshotCleanup)
932+
933+
stdout := bytes.NewBuffer(nil)
934+
task, err := container.NewTask(ctx, NewIO(bytes.NewBuffer(nil), stdout, bytes.NewBuffer(nil)))
935+
if err != nil {
936+
t.Error(err)
937+
return
938+
}
939+
defer task.Delete(ctx)
940+
941+
statusC, err := task.Wait(ctx)
942+
if err != nil {
943+
t.Error(err)
944+
return
945+
}
946+
947+
if err := task.Start(ctx); err != nil {
948+
t.Error(err)
949+
return
950+
}
951+
952+
if err := task.Kill(ctx, syscall.SIGKILL); err != nil {
953+
t.Error(err)
954+
}
955+
956+
// Give the shim time to reap the init process and kill the orphans
957+
select {
958+
case <-statusC:
959+
case <-time.After(100 * time.Millisecond):
960+
}
961+
962+
b, err := exec.Command("ps", "ax").CombinedOutput()
963+
if err != nil {
964+
t.Fatal(err)
965+
}
966+
967+
if strings.Contains(string(b), "sleep 42") {
968+
t.Fatalf("killing init didn't kill all its children:\n%v", string(b))
969+
}
970+
971+
if _, err := task.Delete(ctx, WithProcessKill); err != nil {
972+
t.Error(err)
973+
}
974+
}

linux/shim/service.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,14 @@ func (s *Service) checkProcesses(e runc.Exit) {
393393
defer s.mu.Unlock()
394394
for _, p := range s.processes {
395395
if p.Pid() == e.Pid {
396+
if ip, ok := p.(*initProcess); ok {
397+
// Ensure all children are killed
398+
if err := ip.killAll(s.context); err != nil {
399+
log.G(s.context).WithError(err).WithField("id", ip.ID()).
400+
Error("failed to kill init's children")
401+
}
402+
}
403+
396404
p.SetExited(e.Status)
397405
s.events <- &eventsapi.TaskExit{
398406
ContainerID: s.id,

0 commit comments

Comments
 (0)