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

Reply via email to