fix(tmux): add -- to kill commands to prevent procps-ng argument parsing bug (#928)

The procps-ng kill binary (version 4.0.4+) has an argument parsing issue
where negative PIDs like "-12345" are misinterpreted as options because
they start with a dash. This causes the binary to fall back to "-1" which
means "all processes", resulting in kill(-1, signal) being called.

This was discovered through an extensive murder investigation after 26
Claude AI instances were killed when running TestCleanupOrphanedSessions.
Each investigator left notes for their successor, eventually leading to
the discovery that:

- exec.Command("bash", "-c", "kill -KILL -PGID") is SAFE (uses bash builtin)
- exec.Command("kill", "-KILL", "-PGID") is FATAL (uses /usr/bin/kill)

Verified via strace:
  /usr/bin/kill -KILL -12345   → kill(-1, SIGKILL)     # WRONG!
  /usr/bin/kill -KILL -- -12345 → kill(-12345, SIGKILL) # Correct!

The fix adds "--" before negative PGID arguments to explicitly end option
parsing, ensuring the negative number is treated as a PID/PGID argument.

Full investigation: https://github.com/groblegark/gastown/blob/main/MURDER_INVESTIGATION.md

Co-authored-by: Refinery <matthew.baker@pihealth.ai>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
groblegark
2026-01-25 18:01:52 -08:00
committed by GitHub
parent 8a8603e6df
commit 57f062a9b6

View File

@@ -187,10 +187,13 @@ func (t *Tmux) KillSessionWithProcesses(name string) error {
if pgid != "" && pgid != "0" && pgid != "1" {
// Kill process group with negative PGID (POSIX convention)
// Use SIGTERM first for graceful shutdown
_ = exec.Command("kill", "-TERM", "-"+pgid).Run()
// NOTE: The "--" is CRITICAL! Without it, procps-ng kill (v4.0.4+)
// misparses "-PGID" as an option and ends up calling kill(-1) which
// kills ALL processes! See https://github.com/groblegark/gastown/blob/main/MURDER_INVESTIGATION.md
_ = exec.Command("kill", "-TERM", "--", "-"+pgid).Run()
time.Sleep(100 * time.Millisecond)
// Force kill any remaining processes in the group
_ = exec.Command("kill", "-KILL", "-"+pgid).Run()
_ = exec.Command("kill", "-KILL", "--", "-"+pgid).Run()
}
// Also walk the process tree for any descendants that might have called setsid()
@@ -388,9 +391,10 @@ func (t *Tmux) KillPaneProcesses(pane string) error {
pgid := getProcessGroupID(pid)
if pgid != "" && pgid != "0" && pgid != "1" {
// Kill process group with negative PGID (POSIX convention)
_ = exec.Command("kill", "-TERM", "-"+pgid).Run()
// NOTE: The "--" is CRITICAL! See comment in KillSessionWithProcesses.
_ = exec.Command("kill", "-TERM", "--", "-"+pgid).Run()
time.Sleep(100 * time.Millisecond)
_ = exec.Command("kill", "-KILL", "-"+pgid).Run()
_ = exec.Command("kill", "-KILL", "--", "-"+pgid).Run()
}
// Also walk the process tree for any descendants that might have called setsid()