Bug #76167 [NEW]: mbstring may use/efree() pointer from some previous request
| From: | cataphract@php.net | Date: | Fri, 30 Mar 2018 11:25:56 +0000 |
| Subject: | Bug #76167 [NEW]: mbstring may use/efree() pointer from some previous request | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-214537@lists.php.net to get a copy of this message | ||
From: cataphract
Operating system: irrelevant
PHP version: 5.6.35
Package: mbstring related
Bug Type: Bug
Bug description:mbstring may use/efree() pointer from some previous request
Description:
------------
mbstring seems to assume that calls to rinit are matched with calls to
rshutdown, but this may not be case. In particular, if another extension
fails its rinit (after mbstring has run its), either by returning
FAILURE or calling zend_error(), then rshutdown will never be called, as
PG(modules_activated) will be 0.
when mbstring_globals.current_detect_order_list is allocated a pointer,
this pointer is freed in rshutdown:
PHP_RSHUTDOWN_FUNCTION(mbstring)
{
const struct mb_overload_def *p;
zend_function *orig;
if (MBSTRG(current_detect_order_list) != NULL) {
efree(MBSTRG(current_detect_order_list));
MBSTRG(current_detect_order_list) = NULL;
MBSTRG(current_detect_order_list_size) = 0;
}
At this point, the pointer stored by current_detect_order_list may not
be valid anymore, because it may have come from another request. This is
because the per-request initialization of current_detect_order_list is
not unconditional:
static void php_mb_populate_current_detect_order_list(TSRMLS_D)
{
const mbfl_encoding **entry = 0;
size_t nentries;
if (MBSTRG(current_detect_order_list)) {
return;
}
If current_detect_order_list is filled with an invalid pointer from a
previous request, it will stay so.
php_mb_populate_current_detect_order_list() is called from RINIT.
Solution: make php_mb_populate_current_detect_order_list() execute
unconditionally.
Expected result:
----------------
no crash
Actual result:
--------------
gdb session (line numbers are for 5.6.31, but it also happens in
5.6.35):
Hardware watchpoint 1: *mbstring_globals.current_detect_order_list
Breakpoint 2 at 0x7f841794defe: file /tmp/php/ext/mbstring/mbstring.c,
line 4620.
Breakpoint 3 at 0x7f8421d8350a: file /tmp/php/main/main.c, line 1617.
Breakpoint 4 at 0x7f8421d83c16: file /tmp/php/main/main.c, line 1819.
Breakpoint 5 at 0x7f84179420bb: file /tmp/php/ext/mbstring/mbstring.c,
line 1662.
(gdb) c
Continuing.
Breakpoint 3, php_request_startup () at /tmp/php/main/main.c:1617
1617 {
(gdb)
Continuing.
Breakpoint 2, php_mb_populate_current_detect_order_list () at
/tmp/php/ext/mbstring/mbstring.c:4620
4620 const mbfl_encoding **entry = 0;
(gdb)
Continuing.
Hardware watchpoint 1: *mbstring_globals.current_detect_order_list
Old value = <unreadable>
New value = (const mbfl_encoding *) 0x7f8417c6bb20
<mbfl_encoding_ascii>
php_mb_populate_current_detect_order_list () at
/tmp/php/ext/mbstring/mbstring.c:4641
4641 MBSTRG(current_detect_order_list_size) = nentries;
(gdb)
Continuing.
Breakpoint 4, php_request_shutdown (dummy=0x0) at
/tmp/php/main/main.c:1819
1819 {
(gdb)
Continuing.
Breakpoint 3, php_request_startup () at /tmp/php/main/main.c:1617
1617 {
(gdb)
Continuing.
Breakpoint 2, php_mb_populate_current_detect_order_list () at
/tmp/php/ext/mbstring/mbstring.c:4620
4620 const mbfl_encoding **entry = 0;
(gdb)
Continuing.
Hardware watchpoint 1: *mbstring_globals.current_detect_order_list
Old value = (const mbfl_encoding *) 0x7f8417c6bb20
<mbfl_encoding_ascii>
New value = (const mbfl_encoding *) 0x7f8425baebb0
_array_init (arg=0x7f8425baeb38, size=0, __zend_filename=0x7f8421fd7a4e
"/tmp/php/main/php_variables.c", __zend_lineno=630) at
/tmp/php/Zend/zend_API.c:1013
1013 _zend_hash_init(Z_ARRVAL_P(arg), size, ZVAL_PTR_DTOR, 0
ZEND_FILE_LINE_RELAY_CC);
(gdb)
Continuing.
Breakpoint 4, php_request_shutdown (dummy=0x0) at
/tmp/php/main/main.c:1819
1819 {
(gdb)
Continuing.
Hardware watchpoint 1: *mbstring_globals.current_detect_order_list
Old value = (const mbfl_encoding *) 0x7f8425baebb0
New value = (const mbfl_encoding *) 0x5a5a5a5a5a5a5a5a
__memset_avx2 () at ../sysdeps/x86_64/multiarch/memset-avx2.S:86
86 ../sysdeps/x86_64/multiarch/memset-avx2.S: No such file or
directory.
(gdb)
Continuing.
Breakpoint 3, php_request_startup () at /tmp/php/main/main.c:1617
1617 {
(gdb)
Continuing.
Hardware watchpoint 1: *mbstring_globals.current_detect_order_list
Old value = (const mbfl_encoding *) 0x5a5a5a5a5a5a5a5a
New value = (const mbfl_encoding *) 0x0
__memset_avx2 () at ../sysdeps/x86_64/multiarch/memset-avx2.S:144
144 ../sysdeps/x86_64/multiarch/memset-avx2.S: No such file or
directory.
(gdb)
Continuing.
Breakpoint 2, php_mb_populate_current_detect_order_list () at
/tmp/php/ext/mbstring/mbstring.c:4620
4620 const mbfl_encoding **entry = 0;
(gdb)
Continuing.
Breakpoint 4, php_request_shutdown (dummy=0x0) at
/tmp/php/main/main.c:1819
1819 {
(gdb)
Continuing.
Breakpoint 5, zm_deactivate_mbstring (type=1, module_number=24) at
/tmp/php/ext/mbstring/mbstring.c:1662
1662 {
(gdb)
Continuing.
Program received signal SIGSEGV, Segmentation fault.
0x00007f8421de5a94 in zend_mm_check_ptr (heap=0x55b843b361d0,
ptr=0x7f8425baeb38, silent=0, __zend_filename=0x7f8417a50328
"/tmp/php/ext/mbstring/mbstring.c",
__zend_lineno=1667, __zend_orig_filename=0x0, __zend_orig_lineno=0)
at /tmp/php/Zend/zend_alloc.c:1393
1393 ZEND_MM_PREV_BLOCK(p)->info._size != p->info._prev) {
--
Edit bug report at https://bugs.php.net/bug.php?id=76167&edit=1
--
Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=76167&r=trysnapshot54
Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=76167&r=trysnapshot55
Try a snapshot (trunk): https://bugs.php.net/fix.php?id=76167&r=trysnapshottrunk
Fixed in SVN: https://bugs.php.net/fix.php?id=76167&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=76167&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=76167&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=76167&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=76167&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=76167&r=support
Expected behavior: https://bugs.php.net/fix.php?id=76167&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=76167&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=76167&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=76167&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=76167&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=76167&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=76167&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=76167&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=76167&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=76167&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=76167&r=mysqlcfg