From 6c5211a0cef0cc2854eaa387e0eb036e012904d0 Mon Sep 17 00:00:00 2001 From: Stanislav Malyshev Date: Mon, 20 Jun 2016 21:51:42 -0700 Subject: [PATCH] Fix bug #72455: Heap Overflow due to integer overflows --- ext/mcrypt/mcrypt.c | 92 ++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/ext/mcrypt/mcrypt.c b/ext/mcrypt/mcrypt.c index 194660d864eaf..3cbb913414a58 100644 --- a/ext/mcrypt/mcrypt.c +++ b/ext/mcrypt/mcrypt.c @@ -44,7 +44,7 @@ static int le_mcrypt; -typedef struct _php_mcrypt { +typedef struct _php_mcrypt { MCRYPT td; zend_bool init; } php_mcrypt; @@ -292,7 +292,7 @@ ZEND_DECLARE_MODULE_GLOBALS(mcrypt) zend_module_entry mcrypt_module_entry = { STANDARD_MODULE_HEADER, - "mcrypt", + "mcrypt", mcrypt_functions, PHP_MINIT(mcrypt), PHP_MSHUTDOWN(mcrypt), NULL, NULL, @@ -376,7 +376,7 @@ ZEND_GET_MODULE(mcrypt) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &mcryptind) == FAILURE) { \ return; \ } \ - ZEND_FETCH_RESOURCE (pm, php_mcrypt *, &mcryptind, -1, "MCrypt", le_mcrypt); + ZEND_FETCH_RESOURCE (pm, php_mcrypt *, &mcryptind, -1, "MCrypt", le_mcrypt); #define MCRYPT_GET_MODE_DIR_ARGS(DIRECTORY) \ char *dir = NULL; \ @@ -407,7 +407,7 @@ PHP_INI_END() static void php_mcrypt_module_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ { php_mcrypt *pm = (php_mcrypt *) rsrc->ptr; - if (pm) { + if (pm) { mcrypt_generic_deinit(pm->td); mcrypt_module_close(pm->td); efree(pm); @@ -548,7 +548,7 @@ PHP_MINFO_FUNCTION(mcrypt) /* {{{ */ smart_str_free(&tmp1); smart_str_free(&tmp2); php_info_print_table_end(); - + DISPLAY_INI_ENTRIES(); } /* }}} */ @@ -563,17 +563,17 @@ PHP_FUNCTION(mcrypt_module_open) int mode_len, mode_dir_len; MCRYPT td; php_mcrypt *pm; - + if (zend_parse_parameters (ZEND_NUM_ARGS() TSRMLS_CC, "ssss", &cipher, &cipher_len, &cipher_dir, &cipher_dir_len, &mode, &mode_len, &mode_dir, &mode_dir_len)) { return; } - + td = mcrypt_module_open ( cipher, cipher_dir_len > 0 ? cipher_dir : MCG(algorithms_dir), - mode, + mode, mode_dir_len > 0 ? mode_dir : MCG(modes_dir) ); @@ -600,7 +600,7 @@ PHP_FUNCTION(mcrypt_generic_init) int max_key_size, key_size, iv_size; php_mcrypt *pm; int result = 0; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss", &mcryptind, &key, &key_len, &iv, &iv_len) == FAILURE) { return; } @@ -679,7 +679,7 @@ PHP_FUNCTION(mcrypt_generic) if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mcryptind, &data, &data_len) == FAILURE) { return; } - + ZEND_FETCH_RESOURCE(pm, php_mcrypt *, &mcryptind, -1, "MCrypt", le_mcrypt); PHP_MCRYPT_INIT_CHECK @@ -692,6 +692,10 @@ PHP_FUNCTION(mcrypt_generic) if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */ block_size = mcrypt_enc_get_block_size(pm->td); data_size = (((data_len - 1) / block_size) + 1) * block_size; + if (data_size <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Integer overflow in data size"); + RETURN_FALSE; + } data_s = emalloc(data_size + 1); memset(data_s, 0, data_size); memcpy(data_s, data, data_len); @@ -701,7 +705,7 @@ PHP_FUNCTION(mcrypt_generic) memset(data_s, 0, data_size); memcpy(data_s, data, data_len); } - + mcrypt_generic(pm->td, data_s, data_size); data_s[data_size] = '\0'; @@ -720,11 +724,11 @@ PHP_FUNCTION(mdecrypt_generic) php_mcrypt *pm; char* data_s; int block_size, data_size; - + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs", &mcryptind, &data, &data_len) == FAILURE) { return; } - + ZEND_FETCH_RESOURCE(pm, php_mcrypt * , &mcryptind, -1, "MCrypt", le_mcrypt); PHP_MCRYPT_INIT_CHECK @@ -737,6 +741,10 @@ PHP_FUNCTION(mdecrypt_generic) if (mcrypt_enc_is_block_mode(pm->td) == 1) { /* It's a block algorithm */ block_size = mcrypt_enc_get_block_size(pm->td); data_size = (((data_len - 1) / block_size) + 1) * block_size; + if (data_size <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Integer overflow in data size"); + RETURN_FALSE; + } data_s = emalloc(data_size + 1); memset(data_s, 0, data_size); memcpy(data_s, data, data_len); @@ -746,7 +754,7 @@ PHP_FUNCTION(mdecrypt_generic) memset(data_s, 0, data_size); memcpy(data_s, data, data_len); } - + mdecrypt_generic(pm->td, data_s, data_size); RETVAL_STRINGL(data_s, data_size, 1); @@ -760,7 +768,7 @@ PHP_FUNCTION(mcrypt_enc_get_supported_key_sizes) { int i, count = 0; int *key_sizes; - + MCRYPT_GET_TD_ARG array_init(return_value); @@ -829,7 +837,7 @@ PHP_FUNCTION(mcrypt_enc_is_block_algorithm) MCRYPT_GET_TD_ARG if (mcrypt_enc_is_block_algorithm(pm->td) == 1) { - RETURN_TRUE + RETURN_TRUE } else { RETURN_FALSE } @@ -908,7 +916,7 @@ PHP_FUNCTION(mcrypt_enc_get_modes_name) PHP_FUNCTION(mcrypt_module_self_test) { MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir); - + if (mcrypt_module_self_test(module, dir) == 0) { RETURN_TRUE; } else { @@ -922,7 +930,7 @@ PHP_FUNCTION(mcrypt_module_self_test) PHP_FUNCTION(mcrypt_module_is_block_algorithm_mode) { MCRYPT_GET_MODE_DIR_ARGS(modes_dir) - + if (mcrypt_module_is_block_algorithm_mode(module, dir) == 1) { RETURN_TRUE; } else { @@ -936,7 +944,7 @@ PHP_FUNCTION(mcrypt_module_is_block_algorithm_mode) PHP_FUNCTION(mcrypt_module_is_block_algorithm) { MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir) - + if (mcrypt_module_is_block_algorithm(module, dir) == 1) { RETURN_TRUE; } else { @@ -950,7 +958,7 @@ PHP_FUNCTION(mcrypt_module_is_block_algorithm) PHP_FUNCTION(mcrypt_module_is_block_mode) { MCRYPT_GET_MODE_DIR_ARGS(modes_dir) - + if (mcrypt_module_is_block_mode(module, dir) == 1) { RETURN_TRUE; } else { @@ -964,7 +972,7 @@ PHP_FUNCTION(mcrypt_module_is_block_mode) PHP_FUNCTION(mcrypt_module_get_algo_block_size) { MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir) - + RETURN_LONG(mcrypt_module_get_algo_block_size(module, dir)); } /* }}} */ @@ -974,7 +982,7 @@ PHP_FUNCTION(mcrypt_module_get_algo_block_size) PHP_FUNCTION(mcrypt_module_get_algo_key_size) { MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir); - + RETURN_LONG(mcrypt_module_get_algo_key_size(module, dir)); } /* }}} */ @@ -985,7 +993,7 @@ PHP_FUNCTION(mcrypt_module_get_supported_key_sizes) { int i, count = 0; int *key_sizes; - + MCRYPT_GET_MODE_DIR_ARGS(algorithms_dir) array_init(return_value); @@ -1011,7 +1019,7 @@ PHP_FUNCTION(mcrypt_list_algorithms) &lib_dir, &lib_dir_len) == FAILURE) { return; } - + array_init(return_value); modules = mcrypt_list_algorithms(lib_dir, &count); @@ -1058,7 +1066,7 @@ PHP_FUNCTION(mcrypt_get_key_size) { char *cipher; char *module; - int cipher_len, module_len; + int cipher_len, module_len; char *cipher_dir_string; char *module_dir_string; MCRYPT td; @@ -1069,7 +1077,7 @@ PHP_FUNCTION(mcrypt_get_key_size) &cipher, &cipher_len, &module, &module_len) == FAILURE) { return; } - + td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string); if (td != MCRYPT_FAILED) { RETVAL_LONG(mcrypt_enc_get_key_size(td)); @@ -1087,7 +1095,7 @@ PHP_FUNCTION(mcrypt_get_block_size) { char *cipher; char *module; - int cipher_len, module_len; + int cipher_len, module_len; char *cipher_dir_string; char *module_dir_string; MCRYPT td; @@ -1098,7 +1106,7 @@ PHP_FUNCTION(mcrypt_get_block_size) &cipher, &cipher_len, &module, &module_len) == FAILURE) { return; } - + td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string); if (td != MCRYPT_FAILED) { RETVAL_LONG(mcrypt_enc_get_block_size(td)); @@ -1116,7 +1124,7 @@ PHP_FUNCTION(mcrypt_get_iv_size) { char *cipher; char *module; - int cipher_len, module_len; + int cipher_len, module_len; char *cipher_dir_string; char *module_dir_string; MCRYPT td; @@ -1127,7 +1135,7 @@ PHP_FUNCTION(mcrypt_get_iv_size) &cipher, &cipher_len, &module, &module_len) == FAILURE) { return; } - + td = mcrypt_module_open(cipher, cipher_dir_string, module, module_dir_string); if (td != MCRYPT_FAILED) { RETVAL_LONG(mcrypt_enc_get_iv_size(td)); @@ -1217,7 +1225,7 @@ static void php_mcrypt_do_crypt(char* cipher, const char *key, int key_len, cons } else { /* dertermine smallest supported key > length of requested key */ use_key_length = max_key_length; /* start with max key length */ for (i = 0; i < count; i++) { - if (key_length_sizes[i] >= key_len && + if (key_length_sizes[i] >= key_len && key_length_sizes[i] < use_key_length) { use_key_length = key_length_sizes[i]; @@ -1228,11 +1236,11 @@ static void php_mcrypt_do_crypt(char* cipher, const char *key, int key_len, cons memcpy(key_s, key, MIN(key_len, use_key_length)); } mcrypt_free (key_length_sizes); - + /* Check IV */ iv_s = NULL; iv_size = mcrypt_enc_get_iv_size (td); - + /* IV is required */ if (mcrypt_enc_mode_has_iv(td) == 1) { if (argc == 5) { @@ -1272,7 +1280,7 @@ static void php_mcrypt_do_crypt(char* cipher, const char *key, int key_len, cons } else { mdecrypt_generic(td, data_s, data_size); } - + RETVAL_STRINGL(data_s, data_size, 1); /* freeing vars */ @@ -1294,9 +1302,9 @@ PHP_FUNCTION(mcrypt_encrypt) zval **mode; char *cipher, *key, *data, *iv = NULL; int cipher_len, key_len, data_len, iv_len = 0; - + MCRYPT_GET_CRYPT_ARGS - + convert_to_string_ex(mode); php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, Z_STRVAL_PP(mode), iv, iv_len, ZEND_NUM_ARGS(), MCRYPT_ENCRYPT, return_value TSRMLS_CC); @@ -1312,7 +1320,7 @@ PHP_FUNCTION(mcrypt_decrypt) int cipher_len, key_len, data_len, iv_len = 0; MCRYPT_GET_CRYPT_ARGS - + convert_to_string_ex(mode); php_mcrypt_do_crypt(cipher, key, key_len, data, data_len, Z_STRVAL_PP(mode), iv, iv_len, ZEND_NUM_ARGS(), MCRYPT_DECRYPT, return_value TSRMLS_CC); @@ -1326,7 +1334,7 @@ PHP_FUNCTION(mcrypt_ecb) zval **mode; char *cipher, *key, *data, *iv = NULL; int cipher_len, key_len, data_len, iv_len = 0; - + MCRYPT_GET_CRYPT_ARGS convert_to_long_ex(mode); @@ -1358,7 +1366,7 @@ PHP_FUNCTION(mcrypt_cfb) zval **mode; char *cipher, *key, *data, *iv = NULL; int cipher_len, key_len, data_len, iv_len = 0; - + MCRYPT_GET_CRYPT_ARGS convert_to_long_ex(mode); @@ -1374,7 +1382,7 @@ PHP_FUNCTION(mcrypt_ofb) zval **mode; char *cipher, *key, *data, *iv = NULL; int cipher_len, key_len, data_len, iv_len = 0; - + MCRYPT_GET_CRYPT_ARGS convert_to_long_ex(mode); @@ -1400,9 +1408,9 @@ PHP_FUNCTION(mcrypt_create_iv) php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot create an IV with a size of less than 1 or greater than %d", INT_MAX); RETURN_FALSE; } - + iv = ecalloc(size + 1, 1); - + if (source == RANDOM || source == URANDOM) { #if PHP_WIN32 /* random/urandom equivalent on Windows */