Fix infinite loop in DeComp() on empty input - #257
Draft
IrPgFKS0 wants to merge 1 commit into
Draft
Conversation
A zero-length compressed body (e.g. a bare 4-byte "ABG:" frame, which a buggy or malicious peer can send) sizes the output buffer to 0; zlib then returns Z_BUF_ERROR forever because 0 * 2 stays 0 and the 30 MB cap is never reached -- the receive loop spins at 100% CPU for the rest of the session. Reject empty input up front. Also cap the growth at the 30 MB limit (and check with >=) so the limit is actually reachable and a large payload doesn't over-allocate 15 -> 30 -> 60 MB before being rejected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
DeComp()insrc/Compressor.cpploops forever on empty input: a zero-length compressed body (e.g. a bare 4-byteABG:frame, which a buggy or malicious peer can send) sizesoutput_bufferto 0, zlib returnsZ_BUF_ERROR, and the grow stepoutput_buffer.size() * 2stays 0 forever — the 30 MB cap is never reached, so the receive loop spins at 100% CPU for the rest of the session.Two adjacent issues in the same loop:
>while the buffer can only ever equal the value it's compared against after capping — changed to>=;Fix
Reject empty input up front (return an empty buffer — the caller already treats a failed decompress as a dropped packet), cap the growth at the 30 MB limit, and check the cap with
>=. The server'sDeComp(in BeamMP-ServerCommon.cpp) already terminates on this input after its buffer-management rework; this brings the launcher to parity.How this was found
Found during a robustness audit of a LAN fork of BeamMP (the same bug existed in the fork's server base and was reachable from any peer); the fix has been running in that fork for weeks of sessions.
Transparency
This fix comes from an AI-assisted fork: the bug was found and the patch written with the help of an AI coding tool (Claude), then tested by a human in real multiplayer sessions. Given this project's policy on AI-generated code, it's submitted as a draft for the maintainers to decide — happy to close it if that's not wanted, or for a maintainer to re-implement it independently.
🤖 Generated with Claude Code