php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #51583 Bus error due to wrong alignment in mysqlnd
Submitted: 2010-04-17 17:44 UTC Modified: 2010-07-16 05:17 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:0 of 1 (0.0%)
From: rainer dot jung at kippdata dot de Assigned: andrey
Status: Closed Package: MySQL related
PHP Version: 5.3.2 OS: Solaris Sparc
Private report: No CVE-ID:
 [2010-04-17 17:44 UTC] rainer dot jung at kippdata dot de
Description:
------------
Using any of pdo-mysql, mysqli or mysql against mysqlnd results in a bus error on Solaris Sparc. This is due to a wrong alignment assumption that produces crashes because Sparc is strict about alignment.

The resulting core inspected via GDB shows:

Core was generated by `bin/php -c lib/php.ini mysql.php'.
Program terminated with signal 10, Bus error.
#0  0x0027d7f4 in php_mysqlnd_net_send_pub (conn=0x669928, buf=0xffbeee63 "", count=1)
    at /some/path/php53/ext/mysqlnd/mysqlnd_net.c:281
281                             STORE_HEADER_SIZE(safe_storage, p);

(gdb) bt full
#0  0x0027d7f4 in php_mysqlnd_net_send_pub (conn=0x669928, buf=0xffbeee63 "", count=1)
    at /some/path/php53/ext/mysqlnd/mysqlnd_net.c:281
        safe_buf = "\000\000\000"
        net = (MYSQLND_NET *) 0x669370
        old_chunk_size = 8192
        ret = 0
        packets_sent = 1
        left = 1
        p = (zend_uchar *) 0xffbeee63 ""
        compress_buf = (zend_uchar *) 0x0
        to_be_sent = 1
#1  0x0027552c in php_mysqlnd_cmd_write (_packet=0x6692b8, conn=0x669928)
    at /some/path/php53/ext/mysqlnd/mysqlnd_wireprotocol.c:683
        buffer = "\000\000\000\000\001"
        net = (MYSQLND_NET *) 0x669370
        written = <value optimized out>
#2  0x00272154 in php_mysqlnd_conn_simple_command_pub (conn=0x669928, command=COM_QUIT, arg=<value optimized out>, arg_len=<value optimized out>, ok_packet=PROT_LAST,
    silent=1 '\001', ignore_upsert_status=1 '\001') at /some/path/php53/ext/mysqlnd/mysqlnd.c:380
        _p_s = (MYSQLND_STATS *) 0x7efa10
        ret = <value optimized out>
        cmd_packet = (MYSQLND_PACKET_COMMAND *) 0x6692b8
#3  0x0026f920 in mysqlnd_send_close (conn=0x669928) at /some/path/php53/ext/mysqlnd/mysqlnd.c:1393
        ret = <value optimized out>
#4  0x00270560 in php_mysqlnd_conn_close_pub (conn=0x669928, close_type=<value optimized out>)
    at /some/path/php53/ext/mysqlnd/mysqlnd.c:1461
        _p_s = (MYSQLND_STATS *) 0x7dafb8
        stat = STAT_CLOSE_EXPLICIT
        close_type_to_stat_map = {STAT_CLOSE_EXPLICIT, STAT_CLOSE_IMPLICIT, STAT_CLOSE_DISCONNECT}
#5  0xfee47a70 in _close_mysql_link (rsrc=0x672150) at /some/path/php53/ext/mysql/php_mysql.c:355
        link = (php_mysql_conn *) 0x669358
        handler = (void (*)(int)) 0x1
...

(gdb) print p
$1 = (zend_uchar *) 0xffbeee63 ""
(gdb) up
#1  0x0027552c in php_mysqlnd_cmd_write (_packet=0x6692b8, conn=0x669928)
    at /some/path/php53/ext/mysqlnd/mysqlnd_wireprotocol.c:683
683                     written = conn->net->m.send(conn, buffer, 1 TSRMLS_CC);
(gdb) print &buffer
$2 = (char (*)[5]) 0xffbeee63

Further Analysis shows:

- STORE_HEADER_SIZE() is a macro defined in the same file as:
    int4store((safe_storage), (*(uint32_t *)(buffer)))
  Note that "buffer" gets cast via (uint32_t *)

- buffer is not aligned on a 4 byte boundary, in fact it is an odd address.
  In the above example it was allocated in line 680 of mysqlnd_wireprotocol.c,
  without any alignment enforcement: "char buffer[MYSQLND_HEADER_SIZE + 1];"

- thus casting buffer to an (unsigned int *) crashes

Since both macros STORE_HEADER_SIZE and RESTORE_HEADER_SIZE seem to be used in places, where there can be made no assumption about the alignment of the buffer, the attached patch proposes to copy the header bytes as four individual byte operations. Platform specific optimizations might be applied, but at least the patch seems to be a robust solution. The patch was done against trunk, same patch applies with offset to 5_3 branch.

Test script:
---------------
<h2>MySQL Test</h2>
<?php
  ini_set ('display_errors', true);

// Enter your database connection info here
  $db_server = 'myserv';
  $db_port = '3306';
  $db_name = 'mysql';
  $db_username = 'myuser';
  $db_password = 'mypass';

  echo 'Connecting ...<br>';
  $connection = mysql_connect("$db_server:$db_port", $db_username, $db_password, $db_name);
  if (! $connection) {
    echo "<br><b>ERROR - Unable to connect to database server '$db_server:$db_port': ". mysql_error() . '</b><br>';
    return FALSE;
  }
  echo 'Host Info: ' . mysql_get_host_info() . '<br>';
  echo 'Server Info: ' . mysql_get_server_info() . '<br>';
  echo 'Protocol Info: ' . mysql_get_proto_info() . '<br>';
  echo 'Client Info: ' . mysql_get_client_info() . '<br>';
  mysql_close($connection);
?>


Expected result:
----------------
<h2>MySQL Test</h2>
Connecting ...<br>Host Info: sorbus-07 via TCP/IP<br>Server Info: 5.0.27-standard<br>Protocol Info: 10<br>Client Info: mysqlnd 5.0.7-dev - 091210 - $Revision: 294543 $<br>

Actual result:
--------------
<h2>MySQL Test</h2>
Connecting ...<br>Host Info: sorbus-07 via TCP/IP<br>Server Info: 5.0.27-standard<br>Protocol Info: 10<br>Client Info: mysqlnd 5.0.7-dev - 091210 - $Revision: 294543 $<br>Bus Error (core dumped)


Note the trailing "Bus Error ..".
The result was produced by running PHP via CLI.


Patches

mysqlnd_net-align-20100417a.patch (last revision 2010-04-17 15:46 UTC) by rainer dot jung at kippdata dot de)

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2010-04-17 18:29 UTC] felipe@php.net
-Status: Open +Status: Feedback -Assigned To: +Assigned To: mysql
 [2010-04-17 18:29 UTC] felipe@php.net
Please try using this snapshot:

  http://snaps.php.net/php5.3-latest.tar.gz
 
For Windows:

  http://windows.php.net/snapshots/


 [2010-04-17 22:55 UTC] rainer dot jung at kippdata dot de
-Status: Feedback +Status: Open
 [2010-04-17 22:55 UTC] rainer dot jung at kippdata dot de
I checked the snapshot. Exactly the same problem. Please have a look at my analysis and patch proposal. Thanks!
 [2010-04-19 17:03 UTC] andrey@php.net
-Status: Open +Status: Verified
 [2010-04-19 17:03 UTC] andrey@php.net
I will take care of this. This week my Linux/Sparc box will be running again.
 [2010-07-06 13:02 UTC] andrey@php.net
-Status: Verified +Status: Closed
 [2010-07-06 13:02 UTC] andrey@php.net
Patch is in branch and trunk, will appear in 5.3.3.

Thanks!
 [2010-07-15 11:41 UTC] rainer dot jung at kippdata dot de
Sorry to bother you again:

In view of the forthcoming 5.3.3 release I checked today's source code. I can't find any signs of the patch, neither in trunk nor for 5.3.

I then went through the full svn log of ext/mysqlnd for trunk and 5.3 and found no log message which seems to be related to this fix.

Furthermore the full svn log of trunk and 5.3 do not mention the bug number anywhere.

So I doubt whether the patch realy has been applied. Could you please provide the revision number of a subversion commit, where the problem has been fixed?

Thanks,

Rainer
 [2010-07-15 12:22 UTC] aharvey@php.net
-Status: Closed +Status: Re-Opened -Assigned To: mysql +Assigned To: andrey
 [2010-07-15 12:22 UTC] aharvey@php.net
I can't see any evidence of this being fixed on 5.3 or trunk either.

Andrey?
 [2010-07-15 18:57 UTC] andrey@php.net
Automatic comment from SVN on behalf of andrey
Revision: http://svn.php.net/viewvc/?view=revision&amp;revision=301293
Log: Fix for Bug #51583 Bus error due to wrong alignment in mysqlnd
 [2010-07-15 18:58 UTC] andrey@php.net
Oversight, sorry. Now committed, after RC3 was rolled.
 [2010-07-16 05:17 UTC] aharvey@php.net
-Status: Re-Opened +Status: Closed
 [2010-07-16 05:17 UTC] aharvey@php.net
Thanks Andrey.
 
PHP Copyright © 2001-2014 The PHP Group
All rights reserved.
Last updated: Wed Apr 16 10:02:09 2014 UTC