[php-src] Issue #24609: mysqlnd: OK packets without info message rejected on x32 builds since GHSA-r6x9-5r99-36j7 (size_t truncation)

From: Date: Fri, 23 Oct 2026 16:14:34 +0000
Subject: [php-src] Issue #24609: mysqlnd: OK packets without info message rejected on x32 builds since GHSA-r6x9-5r99-36j7 (size_t truncation)
Groups: php.bugs 
Request: Send a blank email to php-bugs+get-253135@lists.php.net to get a copy of this message
Issue: https://github.com/php/php-src/issues/24609 Author: themofleur ### Description Since the fix for GHSA-r6x9-5r99-36j7, every statement answered by an OK packet without an info message (SET NAMES, SET, DO, single-row INSERT or DELETE, TRUNCATE...) fails on x32 builds (ILP32 ABI on x86_64). x86_64 builds of the same versions are not affected. On our hosting, all CLI cron jobs of seven sites have been failing since the CLI binary moved to PHP 8.3.36 (x32 build). The hosting provider reproduced the error and confirmed that it only happens with the x32 build. The following code: ```php <?php mysqli_report(MYSQLI_REPORT_OFF); $link = mysqli_connect('127.0.0.1', 'user', 'password', 'test'); var_dump(mysqli_set_charset($link, 'utf8')); ``` Resulted in this output (x32 build): ``` Warning: mysqli_set_charset(): RSET_HEADER packet additional data length is past 4294967294 bytes the packet size in %s on line 4 Warning: mysqli_set_charset(): Error reading result set's header in %s on line 4 bool(false) ``` Every following query on the same connection then fails with "Commands out of sync; you can't run this command now". But I expected this output instead: ``` bool(true) ``` Root cause: in ext/mysqlnd/mysqlnd_wireprotocol.c, php_mysqlnd_rset_header_read() declares size_t len; (line 1130 on master) and stores in it the zend_ulong returned by php_mysqlnd_net_field_length(). On x32, __x86_64__ is defined, so zend_ulong is 64-bit (Zend/zend_long.h) while size_t is 32-bit. For a minimal OK packet, php_mysqlnd_net_field_length() is called with remaining_size == 0 and returns MYSQLND_INVALID_NET_FIELD_LENGTH ((zend_ulong) -2). Stored in len, it becomes 0xFFFFFFFE, so the check if (len && len != MYSQLND_INVALID_NET_FIELD_LENGTH) (line 1203 on master) no longer recognizes it, and the packet is rejected with an "over-read" of exactly 4294967294 bytes. The other callers of php_mysqlnd_net_field_length() store the result in a zend_ulong and are not affected. i686 builds should not be affected either, since zend_ulong and size_t are both 32-bit there. Suggested fix (not compiled on my side, I cannot build for x32): ```diff --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ php_mysqlnd_rset_header_read - size_t len; + zend_ulong len; ``` len is only used afterwards for values bounded by packet->header.size (LOAD LOCAL file name and info message), so widening it is safe on all platforms. A regression test could use ext/mysqli/tests/fake_server.inc to answer a COM_QUERY with the minimal OK packet "\x00\x00\x00\x02\x00\x00\x00". I also have a standalone script (fake MySQL server started by the script itself, no database needed) and can share it if useful. ### PHP Version ```plain PHP 8.3.36 (x32 build). Same code in PHP 8.2.34+, 8.3.35+, 8.4.26+, 8.5.11+ and master. ``` ### Operating System Linux, x32 ABI (ILP32 on x86_64). x86_64 builds are not affected.

« previous php.bugs (#253135) next »