php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #80713 SegFault when disabling ATTR_EMULATE_PREPARES and MySQL 8.0
Submitted: 2021-02-05 12:56 UTC Modified: 2021-02-16 14:36 UTC
Votes:1
Avg. Score:5.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: php at attrib dot org Assigned: nikic (profile)
Status: Closed Package: PDO MySQL
PHP Version: 7.4.15 OS: Debian Buster
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: php at attrib dot org
New email:
PHP Version: OS:

 

 [2021-02-05 12:56 UTC] php at attrib dot org
Description:
------------
Disabling ATTR_EMULATE_PREPARES produces a segmentation fault when using MySQL 8.0.

See test script.

Test setup:

Running a docker container for mysql (
docker run --rm -it -e MYSQL_ROOT_PASSWORD="test" -e MYSQL_DATABASE="systemA" mysql:8)

With a empty test table (at least id, updated field)

Running the script in a second container using php:7.4.15-cli or php:8.0.2-cli docker image for PHP and running "docker-php-ext-install mysqli pdo_mysql".

Then call the script and the SegFault happens.

gbd output:

(gdb) run mysql.php
Starting program: /usr/local/bin/php mysql.php
warning: Error disabling address space randomization: Operation not permitted
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Program received signal SIGSEGV, Segmentation fault.
0x0000555a8da07eb8 in ?? ()
(gdb) bt
#0  0x0000555a8da07eb8 in ?? ()
#1  0x0000555a8da04429 in ?? ()
#2  0x0000555a8da0e4ff in ?? ()
#3  0x00007f0d5b3f91cc in mysql_handle_preparer ()
   from /usr/local/lib/php/extensions/no-debug-non-zts-20190902/pdo_mysql.so
#4  0x0000555a8d8f38b5 in ?? ()
#5  0x00007f0d5b6514a5 in xdebug_execute_internal (current_execute_data=0x7f0d5b413160, 
    return_value=0x7f0d5b4130d0) at /tmp/pear/temp/xdebug/src/base/base.c:921
#6  0x0000555a8daf853c in execute_ex ()
#7  0x00007f0d5b650ae1 in xdebug_execute_ex (execute_data=0x7f0d5b413020)
    at /tmp/pear/temp/xdebug/src/base/base.c:803
#8  0x0000555a8daf9073 in zend_execute ()
#9  0x0000555a8da731a3 in zend_execute_scripts ()
#10 0x0000555a8da12dd0 in php_execute_script ()
#11 0x0000555a8dafb156 in ?? ()
#12 0x0000555a8d7acb4b in ?? ()
#13 0x00007f0d5e4b909b in __libc_start_main (main=0x555a8d7ac700, argc=2, argv=0x7ffeedecde78, 
    init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7ffeedecde68)
    at ../csu/libc-start.c:308
#14 0x0000555a8d7ad28a in _start ()
(gdb) 


Test script:
---------------
<?php
$pdo = new PDO(sprintf('mysql:dbname=%s;host=%s;charset=utf8', 'systemA', '172.17.0.4:3306'), 'root', 'test', [
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_TIMEOUT => 30,
    PDO::ATTR_EMULATE_PREPARES => false,
]);

$resultAssoc = $pdo->prepare("SELECT * FROM test WHERE :field >= :date ORDER BY :orderBy DESC LIMIT :offset, :limit");
$resultAssoc->execute([
    'field' => 'updated',
    'date' => (new DateTime('2020-02-01'))->format('Y-m-d H:i:s'),
    'orderBy' => 'id',
    'limit' => 1000,
    'offset' => 0,
]);
var_dump($resultAssoc->fetchAll(PDO::FETCH_ASSOC));


Expected result:
----------------
Empty array if nothing is in the DB.

Actual result:
--------------
Segmentation fault (core dumped)

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2021-02-05 12:58 UTC] php at attrib dot org
Forgot to mention, it works if I use mysql:5.7. Only with mysql:8.0
 [2021-02-16 13:36 UTC] nikic@php.net
-Status: Open +Status: Verified
 [2021-02-16 14:11 UTC] nikic@php.net
A bit reduced:

$pdo = new PDO($dsn, 'root', '', [ 
    PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_EMULATE_PREPARES => false,
]);

//$pdo->exec('CREATE TABLE test(updated DATE)');

$stmt = $pdo->prepare("SELECT * FROM test ORDER BY :orderBy DESC");
$stmt->execute(['orderBy' => 'updated']);
var_dump($stmt->fetchAll(PDO::FETCH_ASSOC));

So, obviously the query is invalid (you're trying to prepare an identifier, not a value) and should fail.

This looks like a bug on the MySQL server side, because the server responds with COM_STMT_PREPARE_OK with num_columns=1 and num_params=1, but then directly follows with an EOF in the parameter definition block. The following column definition block is correct.
 [2021-02-16 14:19 UTC] nikic@php.net
Wanted to report this upstream, but apparently you need to fill out https://profile.oracle.com/myprofile/account/create-account.jspx for that, which is a no-go for obvious reasons.

Here is the wireshark dump of the problematic server response:

Frame 16: 152 bytes on wire (1216 bits), 152 bytes captured (1216 bits) on interface lo, id 0
Ethernet II, Src: 00:00:00_00:00:00 (00:00:00:00:00:00), Dst: 00:00:00_00:00:00 (00:00:00:00:00:00)
Internet Protocol Version 4, Src: 127.0.0.1, Dst: 127.0.0.1
Transmission Control Protocol, Src Port: 3306, Dst Port: 42692, Seq: 155, Ack: 188, Len: 86
MySQL Protocol
    Packet Length: 12
    Packet Number: 1
    Response Code: OK Packet (0x00)
    Statement ID: 1
    Number of fields: 1
    Number of parameter: 1
    Warnings: 0
MySQL Protocol
    Packet Length: 5
    Packet Number: 2
    Response Code: EOF Packet (0xfe)
    EOF marker: 254
    Warnings: 0
    Server Status: 0x0002
MySQL Protocol
    Packet Length: 48
    Packet Number: 3
    Catalog: def
    Database: test
    Table: test
    Original table: test
    Name: updated
    Original name: updated
    Charset number: binary COLLATE binary (63)
    Length: 10
    Type: FIELD_TYPE_DATE (10)
    Flags: 0x0080
    Decimals: 0
MySQL Protocol
    Packet Length: 5
    Packet Number: 4
    Response Code: EOF Packet (0xfe)
    EOF marker: 254
    Warnings: 0
    Server Status: 0x0002
 [2021-02-16 14:36 UTC] nikic@php.net
-Status: Verified +Status: Closed -Assigned To: +Assigned To: nikic
 [2021-02-16 14:36 UTC] nikic@php.net
I've committed https://github.com/php/php-src/commit/9552cf6b84b73de38c152b97cc8d30ac3509d4a5 to handle this case more gracefully on our side (we shouldn't crash even if we get an incorrect response...)

I've also tested what happens when libmysqlclient is used instead of mysqlnd, and in that case the script hangs.
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Nov 21 13:01:29 2024 UTC