From ab595c07640eae0c34e5688fc83deb8e6112f5eb Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 13 Oct 2024 20:06:31 +0200 Subject: [PATCH] Fix GH-16411: gmp_export() can cause overflow We need not only to avoid the signed overflow while calculating `bits_per_word` (reported issue), but also the unsigned overflow when calculating `count`. While the former has a fixed threshold, the latter does not, since it also depends on the size in base 2. Thus we use a somewhat unconventional error message. Closes GH-16418. --- NEWS | 1 + ext/gmp/gmp.c | 10 ++++++++-- ext/gmp/tests/gh16411.phpt | 11 +++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 ext/gmp/tests/gh16411.phpt diff --git a/NEWS b/NEWS index a05fdcf4b34..c62a0c0745e 100644 --- a/NEWS +++ b/NEWS @@ -38,6 +38,7 @@ PHP NEWS - GMP: . Fixed floating point exception bug with gmp_pow when using large exposant values. (David Carlier). + . Fixed bug GH-16411 (gmp_export() can cause overflow). (cmb) - MBstring: . Fixed bug GH-16361 (mb_substr overflow on start/length arguments). diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index 2b68d925099..bae141b574a 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -1002,8 +1002,14 @@ ZEND_FUNCTION(gmp_export) if (mpz_sgn(gmpnumber) == 0) { RETVAL_EMPTY_STRING(); } else { - size_t bits_per_word = size * 8; - size_t count = (mpz_sizeinbase(gmpnumber, 2) + bits_per_word - 1) / bits_per_word; + ZEND_ASSERT(size > 0); + size_t size_in_base_2 = mpz_sizeinbase(gmpnumber, 2); + if (size > ZEND_LONG_MAX / 4 || size_in_base_2 > SIZE_MAX - (size_t) size * 8 + 1) { + zend_argument_value_error(2, "is too large for argument #1 ($num)"); + RETURN_THROWS(); + } + size_t bits_per_word = (size_t) size * 8; + size_t count = (size_in_base_2 + bits_per_word - 1) / bits_per_word; zend_string *out_string = zend_string_safe_alloc(count, size, 0, 0); mpz_export(ZSTR_VAL(out_string), NULL, order, size, endian, 0, gmpnumber); diff --git a/ext/gmp/tests/gh16411.phpt b/ext/gmp/tests/gh16411.phpt new file mode 100644 index 00000000000..798943002cf --- /dev/null +++ b/ext/gmp/tests/gh16411.phpt @@ -0,0 +1,11 @@ +--TEST-- +GH-16411 (gmp_export() can cause overflow) +--EXTENSIONS-- +gmp +--FILE-- + +--EXPECTF-- +Fatal error: Uncaught ValueError: gmp_export(): Argument #2 ($word_size) is too large for argument #1 ($num) in %s:%d +%A