andrey Thu, 24 Mar 2011 16:12:18 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=309655
Log: fix buffer overflow - overwriting with 0x0, due to unchecked buffer size. This can be easily workarouned on existing unpatched systems by increasing mysqlnd.net_cmd_buffer_size ini variable to more than 8k Changed paths: U php/php-src/branches/PHP_5_3/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt U php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps_codec.c U php/php-src/trunk/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt U php/php-src/trunk/ext/mysqlnd/mysqlnd_ps_codec.c Modified: php/php-src/branches/PHP_5_3/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt =================================================================== --- php/php-src/branches/PHP_5_3/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt 2011-03-24 15:44:46 UTC (rev 309654) +++ php/php-src/branches/PHP_5_3/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt 2011-03-24 16:12:18 UTC (rev 309655) @@ -115,8 +115,15 @@ <?php require_once("clean_table.inc"); ?> ---XFAIL-- -Statement limits hit, should crash --EXPECTF-- -TODO +Testing 273 columns with 240 rows... +... table created +... statement with 65520 parameters prepared +Statement done +bool(true) +Testing 273 columns with 240 rows... +... table created +... statement with 65520 parameters prepared +Statement done +bool(true) done! \ No newline at end of file Modified: php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps_codec.c =================================================================== --- php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps_codec.c 2011-03-24 15:44:46 UTC (rev 309654) +++ php/php-src/branches/PHP_5_3/ext/mysqlnd/mysqlnd_ps_codec.c 2011-03-24 16:12:18 UTC (rev 309655) @@ -598,8 +598,7 @@ /* {{{ mysqlnd_stmt_execute_store_params */ static enum_func_status -mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, - size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC) +mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s->data; unsigned int i = 0; @@ -609,9 +608,37 @@ zval **copies = NULL;/* if there are different types */ enum_func_status ret = FAIL; int resend_types_next_time = 0; + size_t null_byte_offset; DBG_ENTER("mysqlnd_stmt_execute_store_params"); + { + unsigned int null_count = (stmt->param_count + 7) / 8; + /* give it some reserved space - 20 bytes */ + if (left < (null_count + 20)) { + unsigned int offset = *p - *buf; + zend_uchar *tmp_buf; + *buf_len = offset + null_count + 20; + tmp_buf = mnd_emalloc(*buf_len); + if (!tmp_buf) { + SET_OOM_ERROR(stmt->error_info); + goto end; + } + memcpy(tmp_buf, *buf, offset); + if (*buf != provided_buffer) { + mnd_efree(*buf); + } + *buf = tmp_buf; + + /* Update our pos pointer */ + *p = *buf + offset; + } + /* put `null` bytes */ + null_byte_offset = *p - *buf; + memset(*p, 0, null_count); + *p += null_count; + } + /* 1. Store type information */ /* check if need to send the types even if stmt->send_types_to_server is 0. This is because @@ -660,6 +687,9 @@ goto end; } memcpy(tmp_buf, *buf, offset); + if (*buf != provided_buffer) { + mnd_efree(*buf); + } *buf = tmp_buf; /* Update our pos pointer */ @@ -898,8 +928,6 @@ zend_uchar *p = stmt->execute_cmd_buffer.buffer, *cmd_buffer = stmt->execute_cmd_buffer.buffer; size_t cmd_buffer_length = stmt->execute_cmd_buffer.length; - unsigned int null_byte_offset, - null_count= (stmt->param_count + 7) / 8; enum_func_status ret; DBG_ENTER("mysqlnd_stmt_execute_generate_request"); @@ -917,13 +945,8 @@ int1store(p, 1); /* and send 1 for iteration count */ p+= 4; + ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length TSRMLS_CC); - null_byte_offset = p - cmd_buffer; - memset(p, 0, null_count); - p += null_count; - - ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC); - *free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer); *request_len = (p - cmd_buffer); *request = cmd_buffer; Modified: php/php-src/trunk/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt =================================================================== --- php/php-src/trunk/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt 2011-03-24 15:44:46 UTC (rev 309654) +++ php/php-src/trunk/ext/mysqli/tests/mysqli_stmt_bind_limits.phpt 2011-03-24 16:12:18 UTC (rev 309655) @@ -115,8 +115,15 @@ <?php require_once("clean_table.inc"); ?> ---XFAIL-- -Statement limits hit, should crash --EXPECTF-- -TODO +Testing 273 columns with 240 rows... +... table created +... statement with 65520 parameters prepared +Statement done +bool(true) +Testing 273 columns with 240 rows... +... table created +... statement with 65520 parameters prepared +Statement done +bool(true) done! \ No newline at end of file Modified: php/php-src/trunk/ext/mysqlnd/mysqlnd_ps_codec.c =================================================================== --- php/php-src/trunk/ext/mysqlnd/mysqlnd_ps_codec.c 2011-03-24 15:44:46 UTC (rev 309654) +++ php/php-src/trunk/ext/mysqlnd/mysqlnd_ps_codec.c 2011-03-24 16:12:18 UTC (rev 309655) @@ -585,8 +585,7 @@ /* {{{ mysqlnd_stmt_execute_store_params */ static enum_func_status -mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, - size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC) +mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s->data; unsigned int i = 0; @@ -596,9 +595,37 @@ zval **copies = NULL;/* if there are different types */ enum_func_status ret = FAIL; int resend_types_next_time = 0; + size_t null_byte_offset; DBG_ENTER("mysqlnd_stmt_execute_store_params"); + { + unsigned int null_count = (stmt->param_count + 7) / 8; + /* give it some reserved space - 20 bytes */ + if (left < (null_count + 20)) { + unsigned int offset = *p - *buf; + zend_uchar *tmp_buf; + *buf_len = offset + null_count + 20; + tmp_buf = mnd_emalloc(*buf_len); + if (!tmp_buf) { + SET_OOM_ERROR(stmt->error_info); + goto end; + } + memcpy(tmp_buf, *buf, offset); + if (*buf != provided_buffer) { + mnd_efree(*buf); + } + *buf = tmp_buf; + + /* Update our pos pointer */ + *p = *buf + offset; + } + /* put `null` bytes */ + null_byte_offset = *p - *buf; + memset(*p, 0, null_count); + *p += null_count; + } + /* 1. Store type information */ /* check if need to send the types even if stmt->send_types_to_server is 0. This is because @@ -647,6 +674,9 @@ goto end; } memcpy(tmp_buf, *buf, offset); + if (*buf != provided_buffer) { + mnd_efree(*buf); + } *buf = tmp_buf; /* Update our pos pointer */ @@ -885,8 +915,6 @@ zend_uchar *p = stmt->execute_cmd_buffer.buffer, *cmd_buffer = stmt->execute_cmd_buffer.buffer; size_t cmd_buffer_length = stmt->execute_cmd_buffer.length; - unsigned int null_byte_offset, - null_count= (stmt->param_count + 7) / 8; enum_func_status ret; DBG_ENTER("mysqlnd_stmt_execute_generate_request"); @@ -904,13 +932,8 @@ int1store(p, 1); /* and send 1 for iteration count */ p+= 4; + ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length TSRMLS_CC); - null_byte_offset = p - cmd_buffer; - memset(p, 0, null_count); - p += null_count; - - ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC); - *free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer); *request_len = (p - cmd_buffer); *request = cmd_buffer;
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php