php / php-src

The PHP Interpreter
https://www.php.net
Other
38.08k stars 7.74k forks source link

Double-free due to Pdo\Pgsql::setNoticeCallback() #15986

Closed cmb69 closed 2 weeks ago

cmb69 commented 2 weeks ago

Description

The following code:

<?php
class T { public function z($m) { echo $m."\n"; } public function __call($m, $p) { echo "bah $m\n"; } }
$t = new T;
$rc = new ReflectionClass(Pdo\Pgsql::class);
$db = $rc->newInstanceWithoutConstructor();
$db->setNoticeCallback([ $t, 'disp' ]);

Resulted in this output when ASan is enabled:

Fatal error: Uncaught Error: Pdo\Pgsql object is uninitialized in C:\php-sdk\phpdev\vs17\x64\pdo.php:6
Stack trace:
#0 C:\php-sdk\phpdev\vs17\x64\pdo.php(6): Pdo\Pgsql->setNoticeCallback(Array)
#1 {main}
  thrown in C:\php-sdk\phpdev\vs17\x64\pdo.php on line 6
=================================================================
==7988==ERROR: AddressSanitizer: heap-use-after-free on address 0x125fc0265150 at pc 0x7ffd212fa14f bp 0x00d3297fdc60 sp 0x00d3297fdc68
READ of size 4 at 0x125fc0265150 thread T0
    #0 0x7ffd212fa14e in zend_gc_refcount C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_types.h:1318
    #1 0x7ffd212fa566 in zval_refcount_p C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_types.h:1367
    #2 0x7ffd2130adaa in zval_call_destructor C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_execute_API.c:217
    #3 0x7ffd2133e093 in zend_hash_reverse_apply@@16 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_hash.c:2226
    #4 0x7ffd212fd2ed in shutdown_destructors C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_execute_API.c:262
    #5 0x7ffd20f35566 in zend_call_destructors C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend.c:1325
    #6 0x7ffd215da77c in php_request_shutdown C:\php-sdk\phpdev\vs17\x64\php-src\main\main.c:1912
    #7 0x7ff781407e35 in do_cli C:\php-sdk\phpdev\vs17\x64\php-src\sapi\cli\php_cli.c:1105
    #8 0x7ff781408b8a in main C:\php-sdk\phpdev\vs17\x64\php-src\sapi\cli\php_cli.c:1309
    #9 0x7ff78142dc88 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #10 0x7ff78142dbd1 in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #11 0x7ff78142da8d in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
    #12 0x7ff78142dcfd in mainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:16
    #13 0x7ffd815e7373  (C:\WINDOWS\System32\KERNEL32.DLL+0x180017373)
    #14 0x7ffd8299cc90  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18004cc90)

0x125fc0265150 is located 0 bytes inside of 40-byte region [0x125fc0265150,0x125fc0265178)
freed by thread T0 here:
    #0 0x7ffd3c157788 in _free_dbg D:\a\_work\1\s\src\vctools\asan\llvm\compiler-rt\lib\asan\asan_malloc_win.cpp:240
    #1 0x7ffd20f79267 in __zend_free C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_alloc.c:3308
    #2 0x7ffd20f78ae6 in _efree@@40 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_alloc.c:2747
    #3 0x7ffd214214ca in zend_objects_store_del@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_objects_API.c:198
    #4 0x7ffd2147bd5a in rc_dtor_func@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.c:57
    #5 0x7ffd2134df54 in i_zval_ptr_dtor C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.h:45
    #6 0x7ffd213495af in zend_array_destroy@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_hash.c:1831
    #7 0x7ffd2147bd5a in rc_dtor_func@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.c:57
    #8 0x7ffd2134df54 in i_zval_ptr_dtor C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.h:45
    #9 0x7ffd213495af in zend_array_destroy@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_hash.c:1831
    #10 0x7ffd2147bd5a in rc_dtor_func@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.c:57
    #11 0x7ffd2134df54 in i_zval_ptr_dtor C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.h:45
    #12 0x7ffd21349681 in zend_array_destroy@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_hash.c:1839
    #13 0x7ffd2147bd5a in rc_dtor_func@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.c:57
    #14 0x7ffd2134df54 in i_zval_ptr_dtor C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.h:45
    #15 0x7ffd213495af in zend_array_destroy@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_hash.c:1831
    #16 0x7ffd2147bd5a in rc_dtor_func@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.c:57
    #17 0x7ffd2141c594 in i_zval_ptr_dtor C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_variables.h:45
    #18 0x7ffd2141eb3b in zend_object_dtor_property C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_objects.c:73
    #19 0x7ffd2141db60 in zend_object_std_dtor C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_objects.c:95
    #20 0x7ffd214213ea in zend_objects_store_del@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_objects_API.c:194
    #21 0x7ffd2105edaf in zend_object_release C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_objects_API.h:77
    #22 0x7ffd21061475 in zend_exception_error C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_exceptions.c:964
    #23 0x7ffd20f37c74 in zend_execute_script C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend.c:1934
    #24 0x7ffd215dc861 in php_execute_script_ex C:\php-sdk\phpdev\vs17\x64\php-src\main\main.c:2574
    #25 0x7ffd215dbd64 in php_execute_script C:\php-sdk\phpdev\vs17\x64\php-src\main\main.c:2614
    #26 0x7ff781406f3d in do_cli C:\php-sdk\phpdev\vs17\x64\php-src\sapi\cli\php_cli.c:935
    #27 0x7ff781408b8a in main C:\php-sdk\phpdev\vs17\x64\php-src\sapi\cli\php_cli.c:1309

previously allocated by thread T0 here:
    #0 0x7ffd3c1578c8 in _malloc_dbg D:\a\_work\1\s\src\vctools\asan\llvm\compiler-rt\lib\asan\asan_malloc_win.cpp:263
    #1 0x7ffd20f79114 in __zend_malloc C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_alloc.c:3280
    #2 0x7ffd20f78936 in _emalloc@@40 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_alloc.c:2737
    #3 0x7ffd2141c9c6 in zend_objects_new@@8 C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_objects.c:210
    #4 0x7ffd20f71911 in _object_and_properties_init C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_API.c:1823
    #5 0x7ffd20f562cf in object_init_ex C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_API.c:1846
    #6 0x7ffd2111c25d in ZEND_NEW_SPEC_CONST_UNUSED_HANDLER C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_vm_execute.h:10895
    #7 0x7ffd2107585a in execute_ex C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_vm_execute.h:58486
    #8 0x7ffd21075769 in zend_execute C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_vm_execute.h:64138
    #9 0x7ffd20f37c31 in zend_execute_script C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend.c:1927
    #10 0x7ffd215dc861 in php_execute_script_ex C:\php-sdk\phpdev\vs17\x64\php-src\main\main.c:2574
    #11 0x7ffd215dbd64 in php_execute_script C:\php-sdk\phpdev\vs17\x64\php-src\main\main.c:2614
    #12 0x7ff781406f3d in do_cli C:\php-sdk\phpdev\vs17\x64\php-src\sapi\cli\php_cli.c:935
    #13 0x7ff781408b8a in main C:\php-sdk\phpdev\vs17\x64\php-src\sapi\cli\php_cli.c:1309
    #14 0x7ff78142dc88 in invoke_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:78
    #15 0x7ff78142dbd1 in __scrt_common_main_seh D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288
    #16 0x7ff78142da8d in __scrt_common_main D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:330
    #17 0x7ff78142dcfd in mainCRTStartup D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_main.cpp:16
    #18 0x7ffd815e7373  (C:\WINDOWS\System32\KERNEL32.DLL+0x180017373)
    #19 0x7ffd8299cc90  (C:\WINDOWS\SYSTEM32\ntdll.dll+0x18004cc90)

SUMMARY: AddressSanitizer: heap-use-after-free C:\php-sdk\phpdev\vs17\x64\php-src\Zend\zend_types.h:1318 in zend_gc_refcount
Shadow bytes around the buggy address:
  0x04a3b81cc9d0: fa fa 00 00 00 00 00 fa fa fa fd fd fd fd fd fd
  0x04a3b81cc9e0: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x04a3b81cc9f0: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x04a3b81cca00: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
  0x04a3b81cca10: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fa
=>0x04a3b81cca20: fa fa fd fd fd fd fd fd fa fa[fd]fd fd fd fd fa
  0x04a3b81cca30: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd
  0x04a3b81cca40: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fa
  0x04a3b81cca50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x04a3b81cca60: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x04a3b81cca70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==7988==ABORTING

But I expected this output instead:

Fatal error: Uncaught Error: Pdo\Pgsql object is uninitialized in C:\php-sdk\phpdev\vs17\x64\pdo.php:6
Stack trace:
#0 C:\php-sdk\phpdev\vs17\x64\pdo.php(6): Pdo\Pgsql->setNoticeCallback(Array)
#1 {main}

What about:

 ext/pdo_pgsql/pdo_pgsql.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/ext/pdo_pgsql/pdo_pgsql.c b/ext/pdo_pgsql/pdo_pgsql.c
index caa2caee54..e3e913868d 100644
--- a/ext/pdo_pgsql/pdo_pgsql.c
+++ b/ext/pdo_pgsql/pdo_pgsql.c
@@ -170,7 +170,7 @@ PHP_METHOD(Pdo_Pgsql, setNoticeCallback)

 cleanup:
    if (ZEND_FCC_INITIALIZED(fcc)) {
-       zend_fcc_dtor(&fcc);
+       zend_release_fcall_info_cache(&fcc);
    }
    RETURN_THROWS();
 }

PHP Version

PHP 8.4

Operating System

Windows

nielsdos commented 2 weeks ago

@cmb69 Patch LGTM, I think you can even avoid the check ZEND_FCC_INITIALIZED because zend_release_fcall_info_cache actually does that already for you.