php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #78797 mysqlnd cannot read large OK/ERR packets
Submitted: 2019-11-08 22:54 UTC Modified: -
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: as@php.net Assigned:
Status: Open Package: PDO MySQL
PHP Version: 7.4.0RC5 OS:
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: as@php.net
New email:
PHP Version: OS:

 

 [2019-11-08 22:54 UTC] as@php.net
Description:
------------
mysqlnd hits this condition[0] when it receives an OK/ERR packet larger than `mysqlnd.net_cmd_buffer_size`, resulting in "Error reading result set's header...".

These packets have variable-length fields (e.g., error_message[1]) which are not guaranteed to fit in a statically-sized buffer. I'm unsure if popular MySQL versions (Oracle, Percona, MariaDB) will ever emit such packets, however some niche servers that speak the MySQL protocol (e.g., Vitess) do.

[0] https://github.com/php/php-src/blob/4d529757f84cb81d5eba53e77e8395efe4e54334/ext/mysqlnd/mysqlnd_wireprotocol.c#L300-L304

[1] https://dev.mysql.com/doc/internals/en/packet-ERR_Packet.html


Test script:
---------------
Normal behavior (ERR packet shorter than `mysqlnd.net_cmd_buffer_size`)

```
$ # Fake MySQL server that sends handshake, then OK, then 4kb ERR packet
$ { echo -en "\x34\x00\x00\x00\x0aversion\x00TTTTAAAAAAAA\x00\x00\x00\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; echo -en "\x07\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00"; echo -en "\x00\x10\x00\x01\xff\xff\xff$(for i in {1..4093}; do echo -n A; done)" ; } | nc -l 1234

$ php -n -r '$p = new PDO("mysql:host=127.0.0.1;port=1234", "user", "pass", [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); $p->query("select 1");'

Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 65535 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA in Command line code:1
Stack trace:
#0 Command line code(1): PDO->query('select 1')
#1 {main}
  thrown in Command line code on line 1
```


Bug behavior (ERR packet longer than `mysqlnd.net_cmd_buffer_size`)
```
$ # Fake MySQL server that sends handshake, then OK, then 8kb ERR packet
$ { echo -en "\x34\x00\x00\x00\x0aversion\x00TTTTAAAAAAAA\x00\x00\x00\x3f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; echo -en "\x07\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00"; echo -en "\x00\x20\x00\x01\xff\xff\xff$(for i in {1..8189}; do echo -n A; done)" ; } | nc -l 1234

$ php -n -r '$p = new PDO("mysql:host=127.0.0.1;port=1234", "user", "pass", [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]); $p->query("select 1");'

Warning: PDO::query(): Error reading result set's header in Command line code on line 1
```



Patches

Add a Patch

Pull Requests

Add a Pull Request

 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 14:01:31 2024 UTC