agent: send SIGTERM only to root container process on container deletion

When containerd wants to terminate a container, it sends a KillRequest with exec_id="", all=false, signal=SIGTERM.
Kata-shim translates that to a SignalProcessRequest with exec_id="", signal=SIGTERM
Kata agent used to interpret exec_id="" as implying all=true.
That was correct for forceful deletion of containers, as it uses a KillRequest with all=true, signal=SIGKILL.
However, for graceful termination, we want to only signal the root process of the container (all=false).

This changes makes it so that Kata agent interprets exec_id="" && signal=SIGKILL as implying all=true, and uses all=false otherwise.
It also fixes an unrelated bug, where Kata agent would signal the root process twice when all=true.

Fixes #13152 - sending SIGTERM twice to the container's init process on graceful shutdown of a container.

Signed-off-by: Bozhidar Marinov <bozhidar.marinov1@digits.schwarz>
Co-authored-by: Markus Rudy <webmaster@burgerdev.de>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Bozhidar Marinov
2026-06-03 23:30:26 +03:00
committed by Fabiano Fidêncio
parent ba23b1ad50
commit 2212dbdd48
4 changed files with 131 additions and 6 deletions

View File

@@ -489,6 +489,14 @@ impl AgentService {
async fn do_signal_process(&self, req: protocols::agent::SignalProcessRequest) -> Result<()> {
let cid = req.container_id;
let eid = req.exec_id;
let mut sig: libc::c_int = req.signal as libc::c_int;
let all = eid.is_empty() && sig == libc::SIGKILL;
// NOTE: kata runtime encodes all = true by setting eid = "".
// However, containerd can send eid = "", sig = SIGTERM, all = false when deleting containers
// (and containerd will send eid = "", sig = SIGKILL, all = true when forcefully deleting containers)
// Luckily, containerd never sends eid = "", sig = SIGKILL, all = false outside of ctr
// So we can recover the original value of all here by checking eid and sig
info!(
sl(),
@@ -496,10 +504,10 @@ impl AgentService {
"container-id" => &cid,
"exec-id" => &eid,
"signal" => req.signal,
"all" => all,
);
let mut sig: libc::c_int = req.signal as libc::c_int;
{
if !all {
let mut sandbox = self.sandbox.lock().await;
let p = sandbox
.find_container_process(cid.as_str(), eid.as_str())
@@ -512,6 +520,15 @@ impl AgentService {
sig = libc::SIGKILL;
}
debug!(
sl(),
"signaling a container process";
"container-id" => &cid,
"exec-id" => &eid,
"pid" => p.pid,
"signal" => sig,
);
match p.signal(sig) {
Err(Errno::ESRCH) => {
info!(
@@ -526,10 +543,8 @@ impl AgentService {
Err(err) => return Err(anyhow!(err)),
Ok(()) => (),
}
};
if eid.is_empty() {
// eid is empty, signal all the remaining processes in the container cgroup
} else {
// Signalling all processes in the cgroup
info!(
sl(),
"signal all the remaining processes";