|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2016-09-14 07:48 UTC] secresearch at fortinet dot com
Description:
------------
Multi byte encode function did not check the length of encode data, that cause output length will be overflow the integer and cause heap corruption:
mbfl_string * mbfl_html_numeric_entity(
mbfl_string *string,
mbfl_string *result,
int *convmap,
int mapsize,
int type)
{
...
/* feed data */
p = string->val;
n = string->len;
if (p != NULL) {
while (n > 0) { //this loop will cause the corruption
if ((*encoder->filter_function)(*p++, encoder) < 0) {
break;
}
n--;
}
}
mbfl_memory_device_output(int c, void *data)
{
mbfl_memory_device *device = (mbfl_memory_device *)data;
if (device->pos >= device->length) {
/* reallocate buffer */
int newlen;
unsigned char *tmp;
newlen = device->length + device->allocsz;
tmp = (unsigned char *)mbfl_realloc((void *)device->buffer, newlen*sizeof(unsigned char));
if (tmp == NULL) {
return -1;
}
device->length = newlen;
device->buffer = tmp;
}
device->buffer[device->pos++] = (unsigned char)c; //device->pos = -2147483647 -> crash
return c;
}
Patch:
------------
*check device->pos value in mbfl_memory_device_output
*or just check the output length must accepted (<int_max) in function mbfl_html_numeric_entity
Test script:
---------------
<?php
ini_set('memory_limit', -1);
$str = str_repeat("a", 0xffffffff/9); //a -> a output_len = input_len*5 -> overflow integer
var_dump(strlen($str));
$str1 = mb_encode_numericentity ($str, array (0x0, 0xffff, 0, 0xffff), 'UTF-8');
?>
Expected result:
----------------
No Crash
Actual result:
--------------
Starting program: /home/test/PHP-5.6.26/sapi/cli/php ~/phptestcase/testmb_encode_numericentity_negative.php
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/usr/lib/libthread_db.so.1".
int(2147483646)
Program received signal SIGSEGV, Segmentation fault.
0x000000000070a97a in mbfl_memory_device_output (c=38, data=0x7fffffffa670) at /home/test/PHP-5.6.26/ext/mbstring/libmbfl/mbfl/mbfl_memory_device.c:157
157 device->buffer[device->pos++] = (unsigned char)c;
(gdb) bt
#0 0x000000000070a97a in mbfl_memory_device_output (c=38, data=0x7fffffffa670) at /home/test/PHP-5.6.26/ext/mbstring/libmbfl/mbfl/mbfl_memory_device.c:157
#1 0x0000000000701f74 in mbfl_filt_conv_wchar_utf8 (c=38, filter=0x7ffff7fa12c8) at /home/test/PHP-5.6.26/ext/mbstring/libmbfl/filters/mbfilter_utf8.c:219
#2 0x00000000007083c6 in collector_encode_htmlnumericentity (c=26085, data=0x7fffffffa690) at /home/test/PHP-5.6.26/ext/mbstring/libmbfl/mbfl/mbfilter.c:2700
#3 0x0000000000701cf6 in mbfl_filt_conv_utf8_wchar (c=165, filter=0x7ffff7fa1348) at /home/test/PHP-5.6.26/ext/mbstring/libmbfl/filters/mbfilter_utf8.c:139
#4 0x00000000007093c8 in mbfl_html_numeric_entity (string=0x7fffffffa730, result=0x7fffffffa710, convmap=0x7ffff7fa1b48, mapsize=1, type=0) at /home/test/PHP-5.6.26/ext/mbstring/libmbfl/mbfl/mbfilter.c:3092
#5 0x0000000000714548 in php_mb_numericentity_exec (ht=3, return_value=0x7ffff7fa1298, return_value_ptr=0x7ffff7f6c150, this_ptr=0x0, return_value_used=1, type=0) at /home/test/PHP-5.6.26/ext/mbstring/mbstring.c:3804
#6 0x00000000007145ff in zif_mb_encode_numericentity (ht=3, return_value=0x7ffff7fa1298, return_value_ptr=0x7ffff7f6c150, this_ptr=0x0, return_value_used=1) at /home/test/PHP-5.6.26/ext/mbstring/mbstring.c:3818
#7 0x00000000009ccf9e in zend_do_fcall_common_helper_SPEC (execute_data=0x7ffff7f6c248) at /home/test/PHP-5.6.26/Zend/zend_vm_execute.h:558
#8 0x00000000009d4bce in ZEND_DO_FCALL_SPEC_CONST_HANDLER (execute_data=0x7ffff7f6c248) at /home/test/PHP-5.6.26/Zend/zend_vm_execute.h:2602
#9 0x00000000009cb491 in execute_ex (execute_data=0x7ffff7f6c248) at /home/test/PHP-5.6.26/Zend/zend_vm_execute.h:363
#10 0x00000000009cbe7d in zend_execute (op_array=0x7ffff7fa09e0) at /home/test/PHP-5.6.26/Zend/zend_vm_execute.h:388
#11 0x00000000009873bc in zend_execute_scripts (type=8, retval=0x0, file_count=3) at /home/test/PHP-5.6.26/Zend/zend.c:1341
#12 0x00000000008f826e in php_execute_script (primary_file=0x7fffffffe280) at /home/test/PHP-5.6.26/main/main.c:2613
#13 0x0000000000aaa1b2 in do_cli (argc=2, argv=0x1382960) at /home/test/PHP-5.6.26/sapi/cli/php_cli.c:994
#14 0x0000000000aab200 in main (argc=2, argv=0x1382960) at /home/test/PHP-5.6.26/sapi/cli/php_cli.c:1378
(gdb)
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Fri Nov 07 14:00:02 2025 UTC |
The patch must looks like this: --- PHP-5.6.26_old/ext/mbstring/libmbfl/mbfl/mbfilter.c 2016-09-26 11:54:21.369998637 +0800 +++ PHP-5.6.26/ext/mbstring/libmbfl/mbfl/mbfilter.c 2016-09-26 14:32:27.536978132 +0800 @@ -111,6 +111,7 @@ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46 }; +#define INT_MAX_LIMIT ((1UL << (SIZEOF_INT * 8 - 1)) - 1) /* @@ -3042,7 +3043,7 @@ int n; unsigned char *p; - if (string == NULL || result == NULL) { + if (string == NULL || result == NULL || (string->len > INT_MAX_LIMIT/5)) { return NULL; } mbfl_string_init(result); output_len <= input_len*5 (5 times is the maximum output length, this depend on convmap, type of encode. So I just leave 5 here for quick fix)