diff --git a/internal/runtime/qemu.go b/internal/runtime/qemu.go index dd25702..81f1b9e 100644 --- a/internal/runtime/qemu.go +++ b/internal/runtime/qemu.go @@ -485,6 +485,16 @@ func (q *QEMU) pidOf(name string) int { if err := syscall.Kill(pid, 0); err != nil { return 0 } + // Guard against PID reuse: a stale pidfile from a VM that was killed (e.g. + // by an agent-restart cgroup kill) may hold a PID that the kernel has since + // reused for an unrelated process. Confirm the live process is in fact this + // VM's QEMU by checking its cmdline references the VM's state dir (every + // launch passes -pidfile/-serial/-qmp paths under vmDir). Without this, a + // dead VM reports "running" and is never recovered. + cmdline, err := os.ReadFile(fmt.Sprintf("/proc/%d/cmdline", pid)) + if err != nil || !strings.Contains(string(cmdline), q.vmDir(name)) { + return 0 + } return pid }