Repository navigation
Conversation
Compress::Raw::Bunzip2->new takes $limitOutput as its fifth positional argument; the fourth is $verbosity, which the module documents as ignored. decoded_content passed only four arguments, so the limit landed in $verbosity and was discarded: an 8 MB bomb decoded in full against a 1024 octet limit. The same branch also seeds $output with Bufsize NUL octets to buy the allowance, which Bunzip2 then appends after, so every bzip2 body decoded with a limit set came back prefixed with that padding. And unlike Zlib, Bunzip2 reports BZ_OK rather than BZ_OUTBUFF_FULL when it stops at its allowance, so the existing BZ_OUTBUFF_FULL check never fired. Croak on an unfinished stream under LimitOutput instead.
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.
Compress::Raw::Bunzip2->newtakes$limitOutputas its fifth positional argument; the fourth is$verbosity, whichCompress::Raw::Bzip2documents as "This parameter is ignored".decoded_contentpasses four (Message.pm:398-403), so the limit lands in$verbosityand is discarded.Measured on master, one bzip2 round,
max_body_size(1024):Passing the limit in slot 4 is byte-for-byte identical to passing no limit at all; only slot 5 restricts the output.
Two more things fall out of the same ten lines:
$output = "\0" x Bufsizeto buy the allowance, because Bunzip2 has noBufsizeoption and takes it from what$outputalready holds. WithappendOutputon,bzinflateappends after that padding, so every bzip2 body decoded with a limit set comes back prefixed withmax_body_sizeNUL octets. On master,'hello world'under a 1024 limit returns 1035 octets.BZ_OK(notBZ_OUTBUFF_FULL) when it stops at its allowance, so the existingBZ_OUTBUFF_FULLcheck never fires. With only the slot fixed, the bomb returns silently truncated content instead of croaking.I noticed this while reading #231 - its changelog describes the limit as one "that gzip and bzip2 already honoured", and the bzip2 half of that is not the case. #231 does not touch this branch (
Message.pm:396-430vs its deflate hunks), so the two should not conflict, but this wants a rebase if #231 lands first.The new test rows go into the existing
t/message-decode-bzipbomb.t. The file's current rows pass on master for the wrong reason: the payload is"\0" x 16M, so the NUL padding is indistinguishable from the body, and the triple-bzip2header makes the second round die on the corrupted intermediate. Dropping just theverbosityargument from my fix makes two of those pre-existing rows fail, which is what shows they were never testing the limit.Verification
Perl 5.38.2,
Compress::Raw::Bzip22.204001.prove -l: 672 tests on master, 674 with this change. Four files fail identically in both (t/headers.twantsTest::Differences;t/message-brotli.t,t/message-decode-brotlibomb.t,t/message-decode-zipbomb.twantTest::Needs) - optional deps I could not install, none touching this path.perltidy --profile=.perltidyrc --assert-tidy --no-standard-output --outfile=/dev/null- the commandprecious.tomlissues - exits 0 on both changed files.App::perlvarsandomegasortI could not install; the diff adds no package variables and does not touch.gitignore.verbosityargument'ello world'BZ_STREAM_ENDThe no-limit path is unchanged:
$padis empty, the new croak is gated onLimitOutput, and the existingmax_body_size(undef)assertion still passes.Brotli I could not exercise -
IO::Uncompress::Brotliis not installable here, andt/message-decode-brotlibomb.tfails on master for that reason too. Reading it, brotli passes its limit as an explicitunbro()argument, so it is not affected.Disclosure: prepared with AI assistance (Claude). I reviewed it, reproduced the bypass and the NUL prefix against
decoded_contentdirectly, and verified the red-green and mutation rows myself.