-
Notifications
You must be signed in to change notification settings - Fork 493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix infinite recursion when parsing HTTP chunks #1553
Closed
rousskov
wants to merge
5
commits into
squid-cache:master
from
measurement-factory:SQUID-918-j55-5-chunk-recursion
Closed
Fix infinite recursion when parsing HTTP chunks #1553
rousskov
wants to merge
5
commits into
squid-cache:master
from
measurement-factory:SQUID-918-j55-5-chunk-recursion
Commits on Oct 29, 2023
-
Reject chunked metadata that does not fit our read buffer
This change stops infinite HttpStateData recursion with at-max-capacity inBuf. Such inBuf prevents progress in the following call chain: * processReply() * processReplyBody() and decodeAndWriteReplyBody() * maybeReadVirginBody() * maybeMakeSpaceAvailable() -- tries but fails to quit processing * processReply() To stop recursion, decodeAndWriteReplyBodyI() now predicts that maybeMakeSpaceAvailable() will detect at-max-capacity inBuf and breaks the recursion by declaring a fatal chunked parsing error. XXX: This change addresses a few known infinite recursion cases, but it is conceptually wrong for several (partially overlapping) reasons: 1. It assumes that at-max-capacity inBuf is a permanent state (i.e. things cannot improve with time). This assumption is false. For example, as more space frees up in the adaptation pipeline, we will clear responseBodyBuffer, and Client::calcBufferSpaceToReserve() may allow us to grow inBuf and read more chunked metadata. 2. New decodeAndWriteReplyBody() code assumption that inability (or lack of necessity) to provide usable buffer space implies that chunk metadata is huge is false: calcReadBufferSpaceToReserve() may become zero even with tiny buffered metadata. 3. The resulting recursion termination is arguably accidental. The call loop remains intact, and minor code changes (or unknown use cases) may resurrect the same infinite recursion problem. ---- This change is based on small portions of the stuck official PR squid-cache#736 (i.e. old Factory branch SQUID-533-Optimize-memalloc-server-reads). It does not include many important fixes and improvements from that branch.
Configuration menu - View commit details
-
Copy full SHA for b863a47 - Browse repository at this point
Copy the full SHA b863a47View commit details -
Revert "Reject chunked metadata that does not fit our read buffer"
I am reverting previous commit b631d5a9c933fa849f6887c433020d0125bc08f4 to address the problems identified in that commit message.
Configuration menu - View commit details
-
Copy full SHA for 1e11af4 - Browse repository at this point
Copy the full SHA 1e11af4View commit details -
Fix infinite recursion when parsing HTTP chunks
This change stops infinite HttpStateData recursion with at-max-capacity inBuf. Such inBuf prevents progress in the following call chain: * processReply() * processReplyBody() and decodeAndWriteReplyBody() * maybeReadVirginBody() * maybeMakeSpaceAvailable() -- tries but fails to quit processing * processReply() HttpStateData::maybeMakeSpaceAvailable() no longer calls processReply(), preventing recursion. maybeReadVirginBody() now aborts transactions that would otherwise get stalled due to full read buffer at its maximum capacity. This change requires that all maybeReadVirginBody() callers do actually need more response data to make progress. AFAICT, that (natural) invariant holds. We moved transaction stalling check from maybeMakeSpaceAvailable() into its previous callers. Without that move, maybeMakeSpaceAvailable() would have to handle both abortTransaction() and delayRead() cases. Besides increased code complexity, that would trigger some premature delayRead() calls (at maybeReadVirginBody() time). Deciding whether to delay socket reads is complicated, the delay mechanism is expensive, and delaying may become unnecessary by the time the socket becomes readable, so it is best to continue to only delayRead() at readReply() time, when there is no other choice left. maybeReadVirginBody() mishandled cases where progress was possible, but not _immediately_ -- it did nothing in those cases, probably stalling transactions when maybeMakeSpaceAvailable() returned false but did not call processReply(). This is now fixed: maybeReadVirginBody() now starts waiting for the socket to be ready for reading in those cases, effectively passing control to readReply() that handles them. maybeReadVirginBody() prematurely grew buffer for future socket reads. As a (positive) side effect of the above refactoring, we now delay buffer growth until the actual read(2) time, which is best for performance. Most likely, this premature buffer growth was an accident: maybeReadVirginBody() correctly called maybeMakeSpaceAvailable() with doGrow set to false. However, maybeMakeSpaceAvailable() misinterpreted doGrow as a "do not actually do it" parameter. That bug is now gone. This recursion bug was discovered and detailed by Joshua Rogers at https://megamansec.github.io/Squid-Security-Audit/ where it was filed as "Chunked Encoding Stack Overflow".
Configuration menu - View commit details
-
Copy full SHA for 78b08ec - Browse repository at this point
Copy the full SHA 78b08ecView commit details -
fixup: Removed out-of-scope improvements
These should probably wait until we resume official PR squid-cache#736 (i.e. old Factory branch SQUID-533-Optimize-memalloc-server-reads) work or start pushing tiny minimal PRs in preparation for that.
Configuration menu - View commit details
-
Copy full SHA for 0aa4317 - Browse repository at this point
Copy the full SHA 0aa4317View commit details -
Configuration menu - View commit details
-
Copy full SHA for 43deb3b - Browse repository at this point
Copy the full SHA 43deb3bView commit details
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.