php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73082 string length overflow in mb_encode_* function
Submitted: 2016-09-14 07:48 UTC Modified: 2017-02-13 01:19 UTC
From: secresearch at fortinet dot com Assigned: stas
Status: Closed Package: mbstring related
PHP Version: 5.6.26RC1 OS: ALL
Private report: No CVE-ID:
 [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 -> &#97; 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)

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-09-25 23:08 UTC] stas@php.net
-Summary: memory corruption in mb_encode_* function +Summary: string length overflow in mb_encode_* function -Assigned To: +Assigned To: stas
 [2016-09-25 23:08 UTC] stas@php.net
The fix is in security repo as e1709b7e588cbda71c577f6e5b701713d0c70a23 and in https://gist.github.com/5677c59cc852e4935cad3571a0daf761
 [2016-09-26 04:10 UTC] secresearch at fortinet dot com
How to access this fix e1709b7e588cbda71c577f6e5b701713d0c70a23
 [2016-09-26 06:34 UTC] secresearch at fortinet dot com
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)
 [2016-10-11 23:45 UTC] stas@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e1709b7e588cbda71c577f6e5b701713d0c70a23
Log: Fix bug #73082
 [2016-10-11 23:45 UTC] stas@php.net
-Status: Assigned +Status: Closed
 [2016-10-12 23:35 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e1709b7e588cbda71c577f6e5b701713d0c70a23
Log: Fix bug #73082
 [2016-10-14 02:23 UTC] ab@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e1709b7e588cbda71c577f6e5b701713d0c70a23
Log: Fix bug #73082
 [2016-10-17 10:07 UTC] bwoebi@php.net
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=e1709b7e588cbda71c577f6e5b701713d0c70a23
Log: Fix bug #73082
 [2017-02-13 01:19 UTC] stas@php.net
-Type: Security +Type: Bug
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Tue Aug 29 15:01:52 2017 UTC