From dded5a0253fbfd3c75c6d73a890049c832374545 Mon Sep 17 00:00:00 2001
From: jingrui <jingrui@huawei.com>
Date: Sat, 20 Feb 2021 09:06:22 +0800
Subject: [PATCH] containerd: fix exec event missing due to pid reuse

When many exec request exit at nearly sametime, the Exit can match with
wrong process and return directly, the event for right process will lost
in this case.

time="2021-02-19T21:10:12.250841280+08:00" level=info msg=event Pid=11623 containerID=a32a1b7923db55ebdc7483e2b9cd986e5efc750b989ad3507eb866835e8e37f4 execID=0b412ecaed98f9ea71168599a9363b8aa3b047187eadaa74973bb6c63a66118d module=libcontainerd namespace=moby topic=/tasks/exec-started
time="2021-02-19T21:10:12+08:00" level=info msg="try publish event(1) /tasks/exit &TaskExit{ContainerID:a32a1b7923db55ebdc7483e2b9cd986e5efc750b989ad3507eb866835e8e37f4,ID:0b412ecaed98f9ea71168599a9363b8aa3b047187eadaa74973bb6c63a66118d,Pid:11623,ExitStatus:0,ExitedAt:2021-02-19 21:10:12.27697416 +0800 CST m=+1893.164673481,} <nil>"
time="2021-02-19T21:11:02.944643980+08:00" level=debug msg="starting exec command 64cd335311e9b3c1c11e7360a374e3218efeb02e6578d7bc0811bad3f1820e16 in container a32a1b7923db55ebdc7483e2b9cd986e5efc750b989ad3507eb866835e8e37f4"
time="2021-02-19T21:11:06.201162360+08:00" level=debug msg="event published" ns=moby topic="/tasks/exec-started" type=containerd.events.TaskExecStarted
time="2021-02-19T21:11:57.961615320+08:00" level=warning msg="Ignoring Exit Event, no such exec command found" container=a32a1b7923db55ebdc7483e2b9cd986e5efc750b989ad3507eb866835e8e37f4 exec-id=0b412ecaed98f9ea71168599a9363b8aa3b047187eadaa74973bb6c63a66118d exec-pid=11623

From logs above, execID=0b412ecae with Pid=11623 exit and event
published, but new exec execID=64cd335 command reuse the Pid, but Exit
event still match previous execID=0b412ecae. so exit event for
execID=64cd335 will lost.

Change-Id: If591a282a1cc0305758130a936ee8b92c88acc6c
Signed-off-by: jingrui <jingrui@huawei.com>
---
 runtime/v1/linux/proc/exec.go | 4 ++++
 runtime/v1/shim/service.go    | 6 +++++-
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/runtime/v1/linux/proc/exec.go b/runtime/v1/linux/proc/exec.go
index ea40cb5b8..a5f40bd63 100644
--- a/runtime/v1/linux/proc/exec.go
+++ b/runtime/v1/linux/proc/exec.go
@@ -86,6 +86,10 @@ func (e *execProcess) ExitedAt() time.Time {
 }
 
 func (e *execProcess) SetExited(status int) {
+	e.pid.Lock()
+	e.pid.pid = -1
+	e.pid.Unlock()
+
 	e.mu.Lock()
 	defer e.mu.Unlock()
 
diff --git a/runtime/v1/shim/service.go b/runtime/v1/shim/service.go
index 7e07ab011..7d7327cd8 100644
--- a/runtime/v1/shim/service.go
+++ b/runtime/v1/shim/service.go
@@ -548,8 +548,13 @@ func (s *Service) checkProcesses(e runc.Exit) {
 		log.G(s.context).WithError(err).Error("failed to check shouldKillAll")
 	}
 
+	match := 0
 	for _, p := range s.processes {
 		if p.Pid() == e.Pid {
+			match++
+			if match > 1 {
+				logrus.Warnf("exit for pid=%d match %d processes", e.Pid, match)
+			}
 			if ip, ok := p.(*proc.Init); ok {
 				ns := filepath.Base(filepath.Dir(ip.Bundle))
 				events.ExitAddFile(ns, events.ExitFile(s.id, uint32(e.Pid), uint32(e.Status)), "init exited")
@@ -591,7 +596,6 @@ func (s *Service) checkProcesses(e runc.Exit) {
 				ExitStatus:  uint32(e.Status),
 				ExitedAt:    p.ExitedAt(),
 			}
-			return
 		}
 	}
 }
-- 
2.17.1

