Skip to content

Commit b7c7a22

Browse files
committed
Fix GH-20620: bzcompress() overflow on large source size.
1 parent c8e13af commit b7c7a22

File tree

2 files changed

+26
-1
lines changed

2 files changed

+26
-1
lines changed

ext/bz2/bz2.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -455,11 +455,18 @@ PHP_FUNCTION(bzcompress)
455455
RETURN_THROWS();
456456
}
457457

458+
size_t chunk_len = source_len + (0.01 * source_len) + 600;
459+
460+
if (chunk_len < source_len || chunk_len > UINT_MAX) {
461+
zend_argument_value_error(1, "must be less than or equal to %lu", UINT_MAX);
462+
RETURN_THROWS();
463+
}
464+
458465
/* Assign them to easy to use variables, dest_len is initially the length of the data
459466
+ .01 x length of data + 600 which is the largest size the results of the compression
460467
could possibly be, at least that's what the libbz2 docs say (thanks to jeremy@nirvani.net
461468
for pointing this out). */
462-
dest_len = (unsigned int) (source_len + (0.01 * source_len) + 600);
469+
dest_len = (unsigned int) chunk_len;
463470

464471
/* Allocate the destination buffer */
465472
dest = zend_string_alloc(dest_len, 0);

ext/bz2/tests/gh20620.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Bug GH-20620 (bzcompress with large source)
3+
--EXTENSIONS--
4+
bz2
5+
--SKIPIF--
6+
<?php if (PHP_INT_SIZE != 8) die('skip this test is for 64bit platforms only'); ?>
7+
--INI--
8+
memory_limit=-1
9+
--FILE--
10+
<?php
11+
try {
12+
bzcompress(str_repeat('1', 4295163906));
13+
} catch (\ValueError $e) {
14+
echo $e->getMessage(), PHP_EOL;
15+
}
16+
?>
17+
--EXPECTF--
18+
bzcompress(): Argument #1 ($data) must be less than or equal to %d

0 commit comments

Comments
 (0)