Bug #78549 [PATCH]: Stack overflow due to nested serialized input
| From: | nikic@php.net | Date: | Tue, 24 Sep 2019 10:18:50 +0000 |
| Subject: | Bug #78549 [PATCH]: Stack overflow due to nested serialized input | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-222905@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=78549&edit=1
ID: 78549
Patch added by: nikic@php.net
Reported by: marc dot schoenefeld at gmx dot org
Summary: Stack overflow due to nested serialized input
Status: Verified
Type: Bug
Package: Reproducible crash
Operating System: CentOS 7 / Generic
PHP Version: 7.3.9
Block user comment: N
Private report: N
New Comment:
The following pull request has been associated:
Patch Name: Add max_depth option to unserialize()
On GitHub: https://github.com/php/php-src/pull/4742
Patch: https://github.com/php/php-src/pull/4742.patch
Previous Comments:
------------------------------------------------------------------------
[2019-09-23 11:38:19] nikic@php.net
Fuzzing seems to hit this quite often, so we should probably do something about it.
Script to find the limit:
<?php
$str = 'i:0;';
for ($i = 0; $i < 10000; $i++) {
$str = 'a:1:{i:0;' . $str . '}';
if ($i % 10 == 0) {
echo "$i\n";
unserialize($str);
}
}
var_dump($str);
I get 5620 on a debug build and 7690 on a release/assert build.
Trying the same with O:8:"stdClass":1 I get 4630 and 7690.
We can add an unserialize option for the max_depth and default it to something like 4000.
------------------------------------------------------------------------
[2019-09-16 13:51:59] nikic@php.net
https://gist.githubusercontent.com/nikic/200240ca7830c6e5d587b3b4aad927eb/raw/d8b02e0bb1deca31025dbaf50a46ab4ab792bf68/php_7_3_9_stack_overflow.ser
I doubt we're going to rewriting the unserializer in a non-recursive fashion, so we can either
introduce an arbitrary depth limit, or just ignore this.
------------------------------------------------------------------------
[2019-09-16 13:27:35] marc dot schoenefeld at gmx dot org
The following patch has been added/updated:
Patch Name: php_7_3_9_stack_overflow.ser.zip.b64.patch
Revision: 1568640455
URL: https://bugs.php.net/patch-display.php?bug=78549&patch=php_7_3_9_stack_overflow.ser.zip.b64.patch&revision=1568640455
------------------------------------------------------------------------
[2019-09-16 12:52:31] nikic@php.net
What are the contents of php_7_3_9_stack_overflow.ser? I can imagine, but if you already have the
test case...
------------------------------------------------------------------------
[2019-09-16 12:32:42] marc dot schoenefeld at gmx dot org
Description:
------------
php 7.3.9 (tested with locally compiled build on CentOS 7) can be DoSed with serialized data,
causing a stack overflow scenario [see below].
Test script:
---------------
<?php
$filehandle = fopen($argv[1], "r") or die("Unable to open file!");
$data = fread($filehandle,filesize($argv[1]));
fclose($filehandle);
$string = unserialize($data);
?>
Expected result:
----------------
No crash
Actual result:
--------------
php-7.3.9/sapi/cli/php sertest.php php_7_3_9_stack_overflow.ser
Program received signal SIGSEGV, Segmentation fault.
php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dd240, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1345
1345 zend_long elements = parse_iv(start + 2);
Missing separate debuginfos, use: debuginfo-install libxml2-2.9.1-6.el7_2.3.x86_64
xz-libs-5.2.2-1.el7.x86_64
(gdb) bt
#0 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dd240, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1345
#1 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df268,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dd240) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
#2 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dd100, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1370
#3 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df230,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dd100) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
#4 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dcfc0, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1370
#5 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df1f8,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dcfc0) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
#6 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dce80, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1370
#7 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df1c0,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dce80) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
#8 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dcd40, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1370
#9 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df188,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dcd40) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
#10 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dcc00, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1370
#11 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df150,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dcc00) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
#12 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dcac0, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1370
#13 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df118,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dcac0) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
#14 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dc980, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1370
#15 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df0e0,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dc980) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
#16 php_var_unserialize_internal (rval=rval@entry=0x7fb2a70dc840, p=p@entry=0x7ffe3f34b120,
max=max@entry=0x7fb2a833ad95 "",
var_hash=var_hash@entry=0x7ffe3f34b128, as_key=as_key@entry=0)
at /php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:1370
#17 0x00000000006ca221 in process_nested_data (objprops=0, elements=0, ht=0x7fb2a70df0a8,
var_hash=0x7ffe3f34b128, max=0x7fb2a833ad95 "",
p=0x7ffe3f34b120, rval=0x7fb2a70dc840) at
/php/linux_build/php-7.3.9/ext/standard/var_unserializer.c:502
---Type <return> to continue, or q <return> to quit--- q
Quit
(gdb) disass $pc-12,$pc+10
Dump of assembler code from 0x6ca14e to 0x6ca164:
0x00000000006ca14e <php_var_unserialize_internal+2430>: jne 0x6c9928
<php_var_unserialize_internal+344>
0x00000000006ca154 <php_var_unserialize_internal+2436>: xor esi,esi
0x00000000006ca156 <php_var_unserialize_internal+2438>: add r12,0x3
=> 0x00000000006ca15a <php_var_unserialize_internal+2442>: call 0x42ca21
<parse_iv2>
0x00000000006ca15f <php_var_unserialize_internal+2447>: test rbx,rbx
0x00000000006ca162 <php_var_unserialize_internal+2450>: mov r13,rax
End of assembler dump.
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=78549&edit=1