Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NULL pointer dereference in mysqlnd package (#81706) #8058

Closed
mdsnins opened this issue Feb 8, 2022 · 1 comment
Closed

NULL pointer dereference in mysqlnd package (#81706) #8058

mdsnins opened this issue Feb 8, 2022 · 1 comment

Comments

@mdsnins
Copy link
Contributor

mdsnins commented Feb 8, 2022

Description

NOTE: This report is same as https://bugs.php.net/bug.php?id=81706
I write a same issue again in GitHub, because I couldn't get any feedbacks in PHP bugs report system.
This bug results in the invalid memory access inludes NULL dereference (CWE-476), and I hope CVE can be assigned as usual NULL dereference.

Since mysqli_stmt::prepare doesn't initialize any bound results even its preparation is failed, unexpected memory behavior (NULL dereference, segfault at weird address, general protection fault, memory leak) can occur. This can cause Denial of Service surely and might be elaborated to severe security vulnerabilities.

The fault address may vary by changing the number of querying columns, or bound variables. In addition, when I build with Zend debug enabled (--enable-debug), the fault occurs near ip. I attached AddressSanitizer log with PHP 8.2-dev build (without --enable-debug)

I attached two scripts, for null dereference and memory leak. For segmentation fault, I attached AddressSanitizer log as the actual result. And I attached PHP debug build log for memory leak

  • PHP 7.2.34
  • PHP 7.4.27
  • PHP 8.0.14
  • PHP 8.1.1
  • PHP 8.2.0-dev
<?php
// NULL Deref
$mysqli = new mysqli("127.0.0.1", "test", "test", "test");

$stmt = $mysqli->prepare("select 1,2,3");
$stmt->bind_result($a,$a,$a);
$stmt->prepare("");
$stmt->prepare("select ".str_repeat("'A',", 0x1201)."1");
?>


<?php
// Memory leak
$mysqli = new mysqli("127.0.0.1", "test", "test", "test");

$stmt = $mysqli->prepare("select 1,2,3");
$stmt->bind_result($a,$a,$a);
$stmt->prepare("");
$stmt->prepare("select 1");
?>

Resulted in this output:

AddressSanitizer:DEADLYSIGNAL
=================================================================
==5841==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x5637c5781605 bp 0x7fff0d265110 sp 0x7fff0d2650e0 T0)
==5841==The signal is caused by a READ memory access.
==5841==Hint: address points to the zero page.
    #0 0x5637c5781604 in zend_gc_refcount /home/payload/php-src/Zend/zend_types.h:1185
    #1 0x5637c5781604 in zval_refcount_p /home/payload/php-src/Zend/zend_types.h:1234
    #2 0x5637c5781604 in mysqlnd_stmt_separate_result_bind /home/payload/php-src/ext/mysqlnd/mysqlnd_ps.c:1710
    #3 0x5637c57817ec in mysqlnd_mysqlnd_stmt_free_stmt_result_pub /home/payload/php-src/ext/mysqlnd/mysqlnd_ps.c:1737
    #4 0x5637c5781bdf in mysqlnd_mysqlnd_stmt_free_stmt_content_pub /home/payload/php-src/ext/mysqlnd/mysqlnd_ps.c:1780
    #5 0x5637c57828cd in mysqlnd_mysqlnd_stmt_close_on_server_priv /home/payload/php-src/ext/mysqlnd/mysqlnd_ps.c:1859
    #6 0x5637c5782bad in mysqlnd_mysqlnd_stmt_dtor_pub /home/payload/php-src/ext/mysqlnd/mysqlnd_ps.c:1884
    #7 0x5637c51079e7 in php_clear_stmt_bind /home/payload/php-src/ext/mysqli/mysqli.c:157
    #8 0x5637c5107fec in mysqli_stmt_free_storage /home/payload/php-src/ext/mysqli/mysqli.c:246
    #9 0x5637c5e34c15 in zend_objects_store_del /home/payload/php-src/Zend/zend_objects_API.c:200
    #10 0x5637c595b738 in rc_dtor_func /home/payload/php-src/Zend/zend_variables.c:57
    #11 0x5637c595bb51 in i_zval_ptr_dtor /home/payload/php-src/Zend/zend_variables.h:44
    #12 0x5637c595bb51 in zval_ptr_dtor /home/payload/php-src/Zend/zend_variables.c:84
    #13 0x5637c59de270 in _zend_hash_del_el_ex /home/payload/php-src/Zend/zend_hash.c:1411
    #14 0x5637c59de270 in _zend_hash_del_el /home/payload/php-src/Zend/zend_hash.c:1438
    #15 0x5637c59de270 in zend_hash_reverse_apply /home/payload/php-src/Zend/zend_hash.c:2156
    #16 0x5637c590173d in shutdown_destructors /home/payload/php-src/Zend/zend_execute_API.c:252
    #17 0x5637c5968c71 in zend_call_destructors /home/payload/php-src/Zend/zend.c:1225
    #18 0x5637c57940a1 in php_request_shutdown /home/payload/php-src/main/main.c:1808
    #19 0x5637c60335b1 in do_cli /home/payload/php-src/sapi/cli/php_cli.c:1135
    #20 0x5637c60345f8 in main /home/payload/php-src/sapi/cli/php_cli.c:1367
    #21 0x7fc53c01a0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
    #22 0x5637c4e02e8d in _start (/home/payload/php82_asan/bin/php+0x402e8d)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/payload/php-src/Zend/zend_types.h:1185 in zend_gc_refcount
==5841==ABORTING


--------------------------------------------------------------


[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.h(93) :  Freeing 0x00007f27c0401050 (5 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(304) : Actual location (location was relayed)
Last leak repeated 4 times
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/Zend/zend_string.h(150) :  Freeing 0x00007f27c0402c80 (40 bytes), script=/tmp/poc2.php
Last leak repeated 3 times
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_statistics.c(217) :  Freeing 0x00007f27c04030c0 (16 bytes), script=/tmp/poc2.php
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/Zend/zend_vm_execute.h(47621) :  Freeing 0x00007f27c045a6c0 (32 bytes), script=/tmp/poc2.php
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_connection.c(1515) :  Freeing 0x00007f27c045a700 (30 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(349) : Actual location (location was relayed)
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_connection.c(681) :  Freeing 0x00007f27c045a740 (29 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(349) : Actual location (location was relayed)
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_connection.c(1573) :  Freeing 0x00007f27c045b480 (56 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(94) : Actual location (location was relayed)
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_commands.c(641) :  Freeing 0x00007f27c045b4e0 (53 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(349) : Actual location (location was relayed)
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_auth.c(104) :  Freeing 0x00007f27c04601f8 (21 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(94) : Actual location (location was relayed)
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_driver.c(246) :  Freeing 0x00007f27c046c480 (344 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(136) : Actual location (location was relayed)
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/Zend/zend_hash.c(172) :  Freeing 0x00007f27c046c600 (320 bytes), script=/tmp/poc2.php
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_statistics.c(218) :  Freeing 0x00007f27c0479600 (1304 bytes), script=/tmp/poc2.php
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_driver.c(267) :  Freeing 0x00007f27c0482400 (216 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(136) : Actual location (location was relayed)
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_driver.c(224) :  Freeing 0x00007f27c048d140 (240 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(136) : Actual location (location was relayed)
[Wed Jan 19 10:00:20 2022]  Script:  '/tmp/poc2.php'
/home/payload/php-src/ext/mysqlnd/mysqlnd_driver.c(110) :  Freeing 0x00007f27c049c500 (1208 bytes), script=/tmp/poc2.php
/home/payload/php-src/ext/mysqlnd/mysqlnd_alloc.c(136) : Actual location (location was relayed)
=== Total 22 memory leaks detected ===

But I expected this output instead: Any error shouldn't be thrown

P.S. Since I added some debug output at mysqlnd_ps.c, the detailed line number can be different slightly.

PHP Version

Irrelevent

Operating System

No response

kamil-tekiela added a commit to kamil-tekiela/php-src that referenced this issue Feb 8, 2022
kamil-tekiela added a commit that referenced this issue Feb 14, 2022
* PHP-8.0:
  Fix bug GH-8058 - mysqlnd segfault when prepare fails
kamil-tekiela added a commit that referenced this issue Feb 14, 2022
* PHP-8.1:
  Fix bug GH-8058 - mysqlnd segfault when prepare fails
@kamil-tekiela
Copy link
Member

Thanks! This should be fixed now in PHP 8.0, 8.1 and 8.2

kamil-tekiela added a commit to kamil-tekiela/php-src that referenced this issue Mar 7, 2022
kamil-tekiela added a commit to kamil-tekiela/php-src that referenced this issue Mar 7, 2022
kamil-tekiela added a commit to kamil-tekiela/php-src that referenced this issue Mar 25, 2022
kamil-tekiela added a commit that referenced this issue Mar 31, 2022
kamil-tekiela added a commit that referenced this issue Mar 31, 2022
* PHP-8.0:
  Fix regression from #8058
kamil-tekiela added a commit that referenced this issue Mar 31, 2022
* PHP-8.1:
  Fix regression from #8058
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants
@cmb69 @kamil-tekiela @mdsnins @damianwadley and others