fix: TOCTOU race in close_sessions_for_transport - #77570
fix: TOCTOU race in close_sessions_for_transport#77570eaglezzz0522-cloud wants to merge 1 commit into
Conversation
Duplicate of #77129 — it implements the same transport-ownership revalidation and adds focused regression coverage. |
SummarySeven PRs address or reference the same WS disconnect/session.resume transport-ownership TOCTOU reported by the issue complex. #77129 carries the recorded best-fix verdict for the underlying issues and the corrected race-interleaving regression test; #53525 proposes the same core repair with broader transport-rebind coverage, while the remaining PRs are duplicates or stacked variants. Related pull requests
Duplicates#77205, #77535, and #77570 duplicate the core repair in #77129; #77206 and #77212 are stacked/recombined variants of that repair plus the RAH-05 test. #53525 overlaps on the core fix but retains a distinct broader transport-rebind salvage path. Suggested consolidationKeep open #77129 with a salvage path as the consolidated implementation: retain its fix plus the deterministic real-interleaving regression test, consistent with the recorded best-fix verdicts and the [contributor:50 commits] consolidation decision. Keep #53525 open with a salvage path for its broader prompt.submit/live-payload/queued-prompt ownership-boundary coverage; close #77570 and #77535 as duplicates of #77129, and retain #77205, #77206, and #77212 as closed duplicate/stacked references. Complex graphflowchart TD
classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
classDef best stroke-width:3px,stroke:#b45309
classDef target stroke-width:3px,stroke:#4338ca
I77127(["issue #77127 (open)"])
I77192(["issue #77192 (open)"])
subgraph Dup53525 ["PRs duplicating each other"]
P53525["PR #53525 (open)"]
P77129["PR #77129 (open)"]
P77205["PR #77205 (closed)"]
P77206["PR #77206 (closed)"]
P77212["PR #77212 (closed)"]
P77535["PR #77535 (open)"]
P77570["PR #77570 (open)"]
end
P77570 -.->|partial| I77127
P77570 -.->|partial| I77192
class I77127 open
class I77192 open
class P53525 open
class P77129 open
class P77205 closed
class P77206 closed
class P77212 closed
class P77535 open
class P77570 open
class P77129 best
class P77129 best
class P77129 best
class P77205 best
class P77206 best
class P77212 best
class P77212 best
class P77570 target
click I77127 "https://github.com/NousResearch/hermes-agent/issues/77127"
click I77192 "https://github.com/NousResearch/hermes-agent/issues/77192"
click P53525 "https://github.com/NousResearch/hermes-agent/pull/53525"
click P77129 "https://github.com/NousResearch/hermes-agent/pull/77129"
click P77205 "https://github.com/NousResearch/hermes-agent/pull/77205"
click P77206 "https://github.com/NousResearch/hermes-agent/pull/77206"
click P77212 "https://github.com/NousResearch/hermes-agent/pull/77212"
click P77535 "https://github.com/NousResearch/hermes-agent/pull/77535"
click P77570 "https://github.com/NousResearch/hermes-agent/pull/77570"
Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label). Cross-PR triage: Reviewed 7 pull requests and 3 issues in this complex. Each diff was read against this issue; Assessment working set: 49 kB of PR diffs, 27 kB of issue/PR text, 6 kB of discussion (15 comments), 27 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch. |
Summary
The transport-disconnect teardown in
_close_sessions_for_transporthad a TOCTOU (time-of-check-time-of-use) race: it took a snapshot of owned sessions inside_sessions_lock, then iterated over them without re-validating the transport. A concurrentsession.resumereconnect could rebind a session to a new transport between the snapshot and the close/detach.Changes
tui_gateway/server.py: snapshot session IDs under_sessions_lock, then re-validate each sessions transport under_session_resume_lockbefore acting_session_resume_lockis the same lock used bysession.resumes warm-reuse rebind, so the race is eliminatedVerification
_session_resume_lockusage in_reuse_live_payload_teardown_popped_sessionis used instead of the removed_close_session_by_idfor the close path_schedule_ws_orphan_reap) still fires for detached sessionsCloses #77192