You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
bash deadline kill: a root process started through sudo survives in the task group, and AFT reports a clean timed_out with live_descendants null #830
When a bash task reaches its deadline, AFT sends SIGTERM to the task's process group, waits up to 2 s, then sends SIGKILL to the group (crates/aft/src/bash_background/process.rs:376-395). An unprivileged AFT cannot signal group members owned by another user, so a root process started through sudo survives in the task's own process group, reparented to PID 1, still running. AFT then reports the task as timed_out (exit 124) with live_descendants: null and says nothing about the survivor.
In a debian:stable-slim container: user u with u ALL=(root) NOPASSWD: ALL, aft run standalone as u over NDJSON with scratch storage. Then configure, then a tool_call for bash with timeout: 3000 and this command:
About 4 s after the deadline, bash_status and ps show:
bash_status: status=timed_out exit_code=124 status_reason="killed by the `timeout` of 3s you passed (exit 124)" live_descendants=null
text="Task bash-…: timed_out (exit 124) 5s"
/tmp/marker: TRAP_RAN
ps: PID PPID PGID SID USER CMD
3084 1 3080 3080 root sleep 30 <- still running, in the task's group
Control in the same container, unprivileged: bash -c "trap '' TERM; sleep 30" with the same timeout. The TERM-ignoring sleep is killed by the group SIGKILL, and bash_status reports live_descendants: [].
Mechanism
killpg(pgid, SIGTERM) reaches sudo (same real UID), and sudo relays SIGTERM to its command only. The root bash runs its EXIT trap and exits without killing its foreground child.
killpg(pgid, SIGKILL) gets EPERM for the root-owned members, so the root sleep survives.
terminate_pgid_with does not check the group after the SIGKILL. In this case the descendant sample is null (not taken), not a list.
Main (c719cd4) has the same kill path: the only change to process.rs since v0.62.0 is in tests.
Expected
AFT cannot kill another user's process, but it should not report a clean kill. After the group SIGKILL, enumerate the group again; linux_process_group_members already treats EPERM as "group exists". If members remain, report them in live_descendants and in the text, for example: "1 process survived the kill and is still running: pid 3084, user root, sleep 30. AFT cannot signal processes owned by another user." The same applies to the completion notice.
A command can protect itself on the root side. Both of these left no survivor in the same container:
sudo -n timeout -k 1 2 <cmd>, with a timeout shorter than AFT's;
Activity
mason: never keep a kill survivor's arguments (#830)
mason: never report a clean kill when survivors are hidden (#830)
mason: type the kill-survivor fields in the bridge and plugins (#830)
mason: match the secret-survivor test on argv0, not the shell's name (#…
mason: say that argv0 falls back to the command name (#830)
mason: keep partial survivors and signal a group that may be alive (#830
mason: signal a finished task's group only with evidence it is still …
mason: recognise a finished task's group by every member found, not o…
mason: report processes that survive a bash kill (#830)
mason: bound the process-group listing at the iterator (#830)
mason: never keep a kill survivor's arguments (#830)
mason: never report a clean kill when survivors are hidden (#830)
mason: type the kill-survivor fields in the bridge and plugins (#830)
mason: match the secret-survivor test on argv0, not the shell's name (#…
mason: say that argv0 falls back to the command name (#830)
mason: keep partial survivors and signal a group that may be alive (#830
mason: signal a finished task's group only with evidence it is still …
mason: recognise a finished task's group by every member found, not o…
mason: pin the approved incomplete-listing sentence (#830)
mason: pass the memory-cap argument in the survivor tests' spawns (#830)
mason: send a kill's completion only after the first group check is s…