Bug #73648 [Opn->Csd]: Heap buffer overflow in substr
| From: | stas@php.net | Date: | Mon, 16 Jan 2017 20:14:31 +0000 |
| Subject: | Bug #73648 [Opn->Csd]: Heap buffer overflow in substr | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-206693@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=73648&edit=1
ID: 73648
Updated by: stas@php.net
Reported by: fernando at null-life dot com
Summary: Heap buffer overflow in substr
-Status: Open
+Status: Closed
Type: Bug
Package: Strings related
Operating System: Linux 32 bits
PHP Version: 7.0.14
Block user comment: N
Private report: N
New Comment:
Automatic comment on behalf of stas
Revision: http://git.php.net/?p=php-src.git;a=commit;h=d1d002fc4dd25a80e20163b18880f40a445276e7
Log: Fix bug #73648 - integer overflow in substr
Previous Comments:
------------------------------------------------------------------------
[2016-12-04 03:28:14] fernando at null-life dot com
Description:
------------
When string parameter length and length parameter are big, integer overflow happens inside
substr's validations, and next buffer overflow happens in memcpy function.
----------------------------------
Source code:
https://github.com/php/php-src/blob/PHP-7.1/ext/standard/string.c#L2384
PHP_FUNCTION(substr)
{
zend_string *str;
zend_long l = 0, f;
int argc = ZEND_NUM_ARGS();
ZEND_PARSE_PARAMETERS_START(2, 3)
Z_PARAM_STR(str)
Z_PARAM_LONG(f)
Z_PARAM_OPTIONAL
Z_PARAM_LONG(l)
ZEND_PARSE_PARAMETERS_END();
if (argc > 2) {
if ((l < 0 && (size_t)(-l) > ZSTR_LEN(str))) {
RETURN_FALSE;
} else if (l > (zend_long)ZSTR_LEN(str)) {
l = ZSTR_LEN(str);
}
} else {
l = ZSTR_LEN(str);
}
if (f > (zend_long)ZSTR_LEN(str)) {
RETURN_FALSE;
} else if (f < 0 && (size_t)-f > ZSTR_LEN(str)) {
f = 0;
}
if (l < 0 && (l + (zend_long)ZSTR_LEN(str) - f) < 0) {
RETURN_FALSE;
}
/* if "from" position is negative, count start position from the end
* of the string
*/
if (f < 0) {
f = (zend_long)ZSTR_LEN(str) + f;
if (f < 0) {
f = 0;
}
}
/* if "length" position is negative, set it to the length
* needed to stop that many chars from the end of the string
*/
if (l < 0) {
l = ((zend_long)ZSTR_LEN(str) - f) + l;
if (l < 0) {
l = 0;
}
}
if ((f + l) > (zend_long)ZSTR_LEN(str)) {
l = ZSTR_LEN(str) - f;
}
RETURN_STRINGL(ZSTR_VAL(str) + f, l);
}
GDB output:
gdb -q --args /home/user/build2/bin/php -n poc.php
Reading symbols from /home/user/build2/bin/php...done.
(gdb) b 2384
Breakpoint 2 at 0x891e316: file /home/user/build2/php-src/ext/standard/string.c, line 2384.
(gdb) c
Continuing.
Breakpoint 2, zif_substr (execute_data=0xf10140c0, return_value=0xffff9a00) at
/home/user/build2/php-src/ext/standard/string.c:2384
2384 if ((f + l) > (zend_long)ZSTR_LEN(str)) {
(gdb) p f
$1 = 2147483646
(gdb) p l
$2 = 33554431
(gdb) p f+l
$3 = -2113929219 // Integer overflow
Test script:
---------------
<?php
ini_set('memory_limit', -1);
$v1=str_repeat("a",0x7FFFFFFF);
$v3=0x1ffffff;
substr($v1, -1, $v3);
Expected result:
----------------
No crash
Actual result:
--------------
ASan output:
==18377==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xef600000 at pc 0xf72caa75 bp
0xffcd4088 sp 0xffcd3c5c
READ of size 33554431 at 0xef600000 thread T0
#0 0xf72caa74 in __asan_memcpy (/usr/lib/i386-linux-gnu/libasan.so.2+0x8aa74)
#1 0xf72cac2f in memcpy (/usr/lib/i386-linux-gnu/libasan.so.2+0x8ac2f)
#2 0x890a78f in zend_string_init /home/user/build2/php-src/Zend/zend_string.h:160
#3 0x891e3e8 in zif_substr /home/user/build2/php-src/ext/standard/string.c:2388
#4 0x8cb669e in ZEND_DO_ICALL_SPEC_RETVAL_UNUSED_HANDLER
/home/user/build2/php-src/Zend/zend_vm_execute.h:628
#5 0x8cb4ed1 in execute_ex /home/user/build2/php-src/Zend/zend_vm_execute.h:429
#6 0x8cb51e4 in zend_execute /home/user/build2/php-src/Zend/zend_vm_execute.h:474
#7 0x8baf604 in zend_execute_scripts /home/user/build2/php-src/Zend/zend.c:1474
#8 0x8a47247 in php_execute_script /home/user/build2/php-src/main/main.c:2533
#9 0x8eaec77 in do_cli /home/user/build2/php-src/sapi/cli/php_cli.c:990
#10 0x8eb1239 in main /home/user/build2/php-src/sapi/cli/php_cli.c:1378
#11 0xf69dd636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
#12 0x806f240 (/home/user/build2/bin/php+0x806f240)
0xef600000 is located 2048 bytes to the left of 114688-byte region [0xef600800,0xef61c800)
allocated by thread T0 here:
#0 0xf72d6dee in malloc (/usr/lib/i386-linux-gnu/libasan.so.2+0x96dee)
#1 0x8c4cb99 in zend_new_interned_string_int /home/user/build2/php-src/Zend/zend_string.c:166
#2 0x8bc98a0 in zend_register_functions /home/user/build2/php-src/Zend/zend_API.c:2237
#3 0x8bcd721 in do_register_internal_class /home/user/build2/php-src/Zend/zend_API.c:2653
#4 0x8bcda85 in zend_register_internal_class /home/user/build2/php-src/Zend/zend_API.c:2701
#5 0x87904b2 in spl_register_std_class /home/user/build2/php-src/ext/spl/spl_functions.c:46
#6 0x8802095 in zm_startup_spl_heap /home/user/build2/php-src/ext/spl/spl_heap.c:1226
#7 0x878fb35 in zm_startup_spl /home/user/build2/php-src/ext/spl/php_spl.c:899
#8 0x8bc5b0d in zend_startup_module_ex /home/user/build2/php-src/Zend/zend_API.c:1843
#9 0x8bc5c21 in zend_startup_module_zval /home/user/build2/php-src/Zend/zend_API.c:1858
#10 0x8bedff0 in zend_hash_apply /home/user/build2/php-src/Zend/zend_hash.c:1508
#11 0x8bc6b36 in zend_startup_modules /home/user/build2/php-src/Zend/zend_API.c:1969
#12 0x8a45dc8 in php_module_startup /home/user/build2/php-src/main/main.c:2256
#13 0x8eac7c2 in php_cli_startup /home/user/build2/php-src/sapi/cli/php_cli.c:424
#14 0x8eb10b8 in main /home/user/build2/php-src/sapi/cli/php_cli.c:1345
#15 0xf69dd636 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x18636)
SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 __asan_memcpy
...
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=73648&edit=1