From 0a1de074de2b6f16234b09223dd30bc822c31009 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Wed, 22 May 2024 22:47:55 +0900 Subject: [PATCH 1/3] ext/bcmath: Prevent overflow of uint32_t/uint64_t. If add more than a certain number of times, it will overflow, so need to adjust the digits before adding. --- ext/bcmath/libbcmath/src/recmul.c | 31 +++++++++++++++---- ext/bcmath/tests/bcmul_check_overflow.phpt | 35 ++++++++++++++++++++++ 2 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 ext/bcmath/tests/bcmul_check_overflow.phpt diff --git a/ext/bcmath/libbcmath/src/recmul.c b/ext/bcmath/libbcmath/src/recmul.c index bfd909f251022..360bc7aacc87e 100644 --- a/ext/bcmath/libbcmath/src/recmul.c +++ b/ext/bcmath/libbcmath/src/recmul.c @@ -33,21 +33,32 @@ #include #include #include +#include #include "private.h" /* For _bc_rm_leading_zeros() */ #include "zend_alloc.h" #if SIZEOF_SIZE_T >= 8 # define BC_MUL_UINT_DIGITS 8 -# define BC_MUL_UINT_OVERFLOW 100000000 +# define BC_MUL_UINT_OVERFLOW (BC_UINT_T) 100000000 +# define BC_MUL_MAX_ADD_COUNT (ULONG_MAX / (BC_MUL_UINT_OVERFLOW * BC_MUL_UINT_OVERFLOW)) #else # define BC_MUL_UINT_DIGITS 4 -# define BC_MUL_UINT_OVERFLOW 10000 +# define BC_MUL_UINT_OVERFLOW (BC_UINT_T) 10000 +# define BC_MUL_MAX_ADD_COUNT (UINT_MAX / (BC_MUL_UINT_OVERFLOW * BC_MUL_UINT_OVERFLOW)) #endif /* Multiply utility routines */ +static inline void bc_digits_adjustment(BC_UINT_T *prod_uint, size_t prod_arr_size) +{ + for (size_t i = 0; i < prod_arr_size - 1; i++) { + prod_uint[i + 1] += prod_uint[i] / BC_MUL_UINT_OVERFLOW; + prod_uint[i] %= BC_MUL_UINT_OVERFLOW; + } +} + /* * Converts BCD to uint, going backwards from pointer n by the number of * characters specified by len. @@ -141,7 +152,18 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc bc_convert_to_uint(n2_uint, n2end, n2len); /* Multiplication and addition */ + size_t count = 0; for (i = 0; i < n1_arr_size; i++) { + /* + * This calculation adds the result multiple times to the array entries. + * When multiplying large numbers of digits, there is a possibility of + * overflow, so digit adjustment is performed beforehand. + */ + if (UNEXPECTED(count >= BC_MUL_MAX_ADD_COUNT)) { + bc_digits_adjustment(prod_uint, prod_arr_size); + count = 0; + } + count++; for (size_t j = 0; j < n2_arr_size; j++) { prod_uint[i + j] += n1_uint[i] * n2_uint[j]; } @@ -151,10 +173,7 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc * Move a value exceeding 4/8 digits by carrying to the next digit. * However, the last digit does nothing. */ - for (i = 0; i < prod_arr_size - 1; i++) { - prod_uint[i + 1] += prod_uint[i] / BC_MUL_UINT_OVERFLOW; - prod_uint[i] %= BC_MUL_UINT_OVERFLOW; - } + bc_digits_adjustment(prod_uint, prod_arr_size); /* Convert to bc_num */ *prod = bc_new_num_nonzeroed(prodlen, 0); diff --git a/ext/bcmath/tests/bcmul_check_overflow.phpt b/ext/bcmath/tests/bcmul_check_overflow.phpt new file mode 100644 index 0000000000000..362e70a85633d --- /dev/null +++ b/ext/bcmath/tests/bcmul_check_overflow.phpt @@ -0,0 +1,35 @@ +--TEST-- +bcmul() checking overflow +--EXTENSIONS-- +bcmath +--INI-- +bcmath.scale=0 +--FILE-- + +--EXPECT-- +2: OK +4: OK +8: OK +16: OK +32: OK +64: OK +128: OK +256: OK +512: OK +1024: OK +2048: OK +4096: OK +8192: OK +16384: OK From 9d109686e1fa9ae8855d85fb2483abb4efbfb831 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Thu, 23 May 2024 01:10:04 +0900 Subject: [PATCH 2/3] Changed the definition method of BC_MUL_MAX_ADD_COUNT --- ext/bcmath/libbcmath/src/recmul.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/bcmath/libbcmath/src/recmul.c b/ext/bcmath/libbcmath/src/recmul.c index 360bc7aacc87e..75d4365fbb130 100644 --- a/ext/bcmath/libbcmath/src/recmul.c +++ b/ext/bcmath/libbcmath/src/recmul.c @@ -41,13 +41,13 @@ #if SIZEOF_SIZE_T >= 8 # define BC_MUL_UINT_DIGITS 8 # define BC_MUL_UINT_OVERFLOW (BC_UINT_T) 100000000 -# define BC_MUL_MAX_ADD_COUNT (ULONG_MAX / (BC_MUL_UINT_OVERFLOW * BC_MUL_UINT_OVERFLOW)) #else # define BC_MUL_UINT_DIGITS 4 # define BC_MUL_UINT_OVERFLOW (BC_UINT_T) 10000 -# define BC_MUL_MAX_ADD_COUNT (UINT_MAX / (BC_MUL_UINT_OVERFLOW * BC_MUL_UINT_OVERFLOW)) #endif +#define BC_MUL_MAX_ADD_COUNT (~((BC_UINT_T) 0) / (BC_MUL_UINT_OVERFLOW * BC_MUL_UINT_OVERFLOW)) + /* Multiply utility routines */ From 73f56835fdf0d9b8d541b2aca6eb37e7e4337cf2 Mon Sep 17 00:00:00 2001 From: Saki Takamachi Date: Thu, 23 May 2024 01:15:43 +0900 Subject: [PATCH 3/3] removed limits.h --- ext/bcmath/libbcmath/src/recmul.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ext/bcmath/libbcmath/src/recmul.c b/ext/bcmath/libbcmath/src/recmul.c index 75d4365fbb130..91d940bb41b8e 100644 --- a/ext/bcmath/libbcmath/src/recmul.c +++ b/ext/bcmath/libbcmath/src/recmul.c @@ -33,7 +33,6 @@ #include #include #include -#include #include "private.h" /* For _bc_rm_leading_zeros() */ #include "zend_alloc.h"