Ensure bcmath scale is between 0 and INT_MAX

Make sure bcmatch scale is between 0 and INT_MAX, both for the
ini setting, and all the functions accepting a scale argument.
A ValueError is thrown if a function argument is out of range.

Closes GH-5455.
This commit is contained in:
Vladyslav Startsev 2020-04-25 02:18:09 +03:00 committed by Nikita Popov
parent 48a34bc120
commit b64aee9706
6 changed files with 177 additions and 36 deletions

View file

@ -45,7 +45,7 @@ zend_module_entry bcmath_module_entry = {
PHP_BCMATH_VERSION,
PHP_MODULE_GLOBALS(bcmath),
PHP_GINIT(bcmath),
PHP_GSHUTDOWN(bcmath),
PHP_GSHUTDOWN(bcmath),
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
@ -57,9 +57,25 @@ ZEND_TSRMLS_CACHE_DEFINE()
ZEND_GET_MODULE(bcmath)
#endif
ZEND_INI_MH(OnUpdateScale)
{
int *p;
zend_long tmp;
tmp = zend_atol(ZSTR_VAL(new_value), ZSTR_LEN(new_value));
if (tmp < 0 || tmp > INT_MAX) {
return FAILURE;
}
p = (int *) ZEND_INI_GET_ADDR();
*p = (int) tmp;
return SUCCESS;
}
/* {{{ PHP_INI */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateLongGEZero, bc_precision, zend_bcmath_globals, bcmath_globals)
STD_PHP_INI_ENTRY("bcmath.scale", "0", PHP_INI_ALL, OnUpdateScale, bc_precision, zend_bcmath_globals, bcmath_globals)
PHP_INI_END()
/* }}} */
@ -142,7 +158,7 @@ PHP_FUNCTION(bcadd)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
@ -152,7 +168,11 @@ PHP_FUNCTION(bcadd)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 3) {
scale = (int) (scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&first);
@ -177,7 +197,7 @@ PHP_FUNCTION(bcsub)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
@ -187,7 +207,11 @@ PHP_FUNCTION(bcsub)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&first);
@ -212,7 +236,7 @@ PHP_FUNCTION(bcmul)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
@ -222,7 +246,11 @@ PHP_FUNCTION(bcmul)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&first);
@ -247,7 +275,7 @@ PHP_FUNCTION(bcdiv)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
@ -257,7 +285,11 @@ PHP_FUNCTION(bcdiv)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&first);
@ -289,7 +321,7 @@ PHP_FUNCTION(bcmod)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
@ -299,7 +331,11 @@ PHP_FUNCTION(bcmod)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&first);
@ -329,18 +365,26 @@ PHP_FUNCTION(bcmod)
PHP_FUNCTION(bcpowmod)
{
zend_string *left, *right, *modulus;
zend_long scale_param = 0;
bc_num first, second, mod, result;
zend_long scale = BCG(bc_precision);
int scale_int;
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(3, 4)
Z_PARAM_STR(left)
Z_PARAM_STR(right)
Z_PARAM_STR(modulus)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(scale)
Z_PARAM_LONG(scale_param)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 4) {
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(4, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&first);
bc_init_num(&second);
bc_init_num(&mod);
@ -349,10 +393,8 @@ PHP_FUNCTION(bcpowmod)
php_str2num(&second, ZSTR_VAL(right));
php_str2num(&mod, ZSTR_VAL(modulus));
scale_int = (int) ((int)scale < 0 ? 0 : scale);
if (bc_raisemod(first, second, mod, &result, scale_int) != -1) {
RETVAL_STR(bc_num2str_ex(result, scale_int));
if (bc_raisemod(first, second, mod, &result, scale) != -1) {
RETVAL_STR(bc_num2str_ex(result, scale));
} else {
RETVAL_FALSE;
}
@ -372,7 +414,7 @@ PHP_FUNCTION(bcpow)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second, result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
@ -382,7 +424,11 @@ PHP_FUNCTION(bcpow)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&first);
@ -407,7 +453,7 @@ PHP_FUNCTION(bcsqrt)
zend_string *left;
zend_long scale_param = 0;
bc_num result;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(left)
@ -416,7 +462,11 @@ PHP_FUNCTION(bcsqrt)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 2) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(2, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&result);
@ -440,7 +490,7 @@ PHP_FUNCTION(bccomp)
zend_string *left, *right;
zend_long scale_param = 0;
bc_num first, second;
int scale = (int)BCG(bc_precision);
int scale = BCG(bc_precision);
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(left)
@ -450,7 +500,11 @@ PHP_FUNCTION(bccomp)
ZEND_PARSE_PARAMETERS_END();
if (ZEND_NUM_ARGS() == 3) {
scale = (int) ((int)scale_param < 0 ? 0 : scale_param);
if (scale_param < 0 || scale_param > INT_MAX) {
zend_argument_value_error(3, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
scale = (int) scale_param;
}
bc_init_num(&first);
@ -460,7 +514,7 @@ PHP_FUNCTION(bccomp)
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
}
if (!bc_str2num(&second, ZSTR_VAL(right), scale)) {
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
php_error_docref(NULL, E_WARNING, "bcmath function argument is not well-formed");
}
RETVAL_LONG(bc_compare(first, second));
@ -484,7 +538,11 @@ PHP_FUNCTION(bcscale)
old_scale = BCG(bc_precision);
if (ZEND_NUM_ARGS() == 1) {
BCG(bc_precision) = ((int)new_scale < 0) ? 0 : new_scale;
if (new_scale < 0 || new_scale > INT_MAX) {
zend_argument_value_error(1, "must be between 0 and %d", INT_MAX);
RETURN_THROWS();
}
BCG(bc_precision) = (int) new_scale;
}
RETURN_LONG(old_scale);