← Commit list

14f6b6b58

Denys Vlasenko
Denys Vlasenko
2026-10-02
SUCCESS Duration: 362s

Subject

bunzip2: reject blocks whose run-length count overflows

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

archival/libarchive/decompress_bunzip2.c+6 -7
@@ -463,13 +463,12 @@ static int get_next_block(bunzip_data *bd)
symbols, but a run of length 0 doesn't mean anything in this
context). Thus space is saved. */
runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
-//The 32-bit overflow of runCnt wasn't yet seen, but probably can happen.
-//This would be the fix (catches too large count way before it can overflow):
-// if (runCnt > bd->dbufSize) {
-// dbg("runCnt:%u > dbufSize:%u RETVAL_DATA_ERROR",
-// runCnt, bd->dbufSize);
-// return RETVAL_DATA_ERROR;
-// }
+ /* Catch 32-bit overflow (we have an example .bz2 file) */
+ if ((int)runCnt < 0) {
+ dbg("runCnt:%u > dbufSize:%u RETVAL_DATA_ERROR",
+ runCnt, bd->dbufSize);
+ return RETVAL_DATA_ERROR;
+ }
if (runPos < bd->dbufSize) runPos <<= 1;
goto end_of_huffman_loop;
}
testsuite/bunzip2.tests+12 -0
@@ -568,6 +568,18 @@ if test "${0##*/}" = "bunzip2.tests"; then
echo "FAIL: $unpack: bz2_issue_12.bz2 corrupted example"
FAILCOUNT=$((FAILCOUNT + 1))
fi
+
+# specially crafted file to attack the
+# runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */
+# code, making (dbufCount + runCnt) overflow 32 bits and become small.
+# (there is a fix now which catches when runCnt reaches 0x80000000)
+ errout="`${bb}bunzip2 <bz2_runcnt_overflow.bz2 2>&1 >/dev/null`"
+ if test x"$errout:$?" = x"bunzip2: bunzip error -5:1"; then
+ echo "PASS: $unpack: bz2_runcnt_overflow.bz2 corrupted example"
+ else
+ echo "FAIL: $unpack: bz2_runcnt_overflow.bz2 corrupted example"
+ FAILCOUNT=$((FAILCOUNT + 1))
+ fi
fi
exit $((FAILCOUNT <= 255 ? FAILCOUNT : 255))
?+0 -0