Repository navigation
[disagg][mooncake] Keep decode status thread alive on bad messages - #32909
guptaishaan wants to merge 1 commit into
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Thanks for working on this issue. The public issue only includes limited details. I removed some technical information to avoid public disclosure. Because of this, the current fix may not fully address the root cause. I have a private Gist with the full report and PoC. I can share it with you privately if that would help. I am also happy to review or test the fix with you. |
|
Thanks, yes, please share it. Since it is still under private disclosure, the GHSA advisory To save you time, here is exactly what this PR does and does not cover, so you can check it
So if the redacted part of the report is about who can reach the socket, or about what a I will hold off on further changes until I have read the report. And yes, testing it against your |
|
Thanks. I have added you to GHSA-98f6-8g99-45hr as a remediation developer. The full report and PoC are available there. This PR appears to address the specific thread termination issue in my report. @ShangmingCai @ByronHsu , could you please review this PR and help move it forward? |
The decode KV manager binds an unauthenticated zmq.PULL socket and decode_thread parses whatever arrives on it with no exception guard. A frame that does not match the status wire format, for example a single frame message hitting the `bootstrap_room, status, prefill_rank = msg` unpack, raises out of the thread and kills it. The process stays up and /health keeps returning 200, so the router keeps sending work to a decode worker whose control path is gone, and later prefill status messages are never processed, leaving requests in WaitingForInput until they time out. Wrap the per-message body in try/except Exception and log with logger.exception, the same shape the mori backend uses for its decode status worker. recv_multipart() stays outside the guard so a dead socket still ends the thread instead of spinning. Add a CPU unit test that binds a real zmq.PULL socket, runs the real start_decode_thread, pushes one malformed frame followed by a valid Success status, and asserts the room still reaches Success.
|
Thanks for confirming, and for adding me to the advisory. The branch had fallen out of merge with main, so I rebased it onto current main Re-verified on the rebased branch: black, isort and ruff are clean, the new test still The items I listed earlier as out of scope are still out of scope here: authenticating @ShangmingCai @ByronHsu one note for whoever picks this up: CI here is red only because |
|
Thanks @guptaishaan. Closing this because you have 7 PRs open and none updated in 7 days, over our soft cap of 5 for idle PRs. Reopen the two or three you most want reviewed - a short active set moves faster than a long idle one. Some directories moved recently, so an older branch may need retargeting: |
Fixes #32652
The decode KV manager binds an unauthenticated
zmq.PULLsocket, anddecode_threadparses whatever arrives on it with no exception guard. A frame that does not match the
status wire format (for example a single-frame message, which hits
bootstrap_room, status, prefill_rank = msg) raises out of the thread and kills it. The process stays upand
/healthkeeps returning 200, so the router keeps routing to a decode worker whosecontrol path is dead, and every later prefill status message is dropped, leaving requests
in
KVPoll.WaitingForInputuntil they time out.Wrap the per-message body of
decode_threadintry/except Exceptionand log withlogger.exception. This is the same shape the mori backend already uses for its decodestatus worker.
recv_multipart()stays outside the guard on purpose: a dead socket shouldstill end the thread rather than spin.
Verified on CPU, no GPU involved. Added
test/registered/unit/disaggregation/test_mooncake_decode_thread.py: it binds a realzmq.PULLsocket, runs the realstart_decode_threadagainst it, pushes one malformedframe followed by a valid Success status for a pending room, and asserts the room reaches
Success. It fails before this change (room stays inWaitingForInput, thread dead) andpasses after. The rest of
test/registered/unit/disaggregation/still passes, and black,isort and ruff are clean on both files.
Not verified: the full 1P1D Mooncake plus router end-to-end scenario from the report. I do
not have that setup, so the repro is at the thread and socket level. The reporter's exact
trigger is under private disclosure, but every parse in the decode status loop is covered
by the guard. Health checks themselves are unchanged: they still cannot see a dead
receiver thread. The prefill-side
bootstrap_threadin the same file has the sameunguarded shape and is left for a follow-up.
Reported by @yyymk, who also filed it privately as GHSA-98f6-8g99-45hr.
CI States
Latest PR Test (Base): ❌ Run #31222996845
Latest PR Test (Extra): ❌ Run #31222998834