|  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #73900 Use After Free in unserialize() SplFixedArray
Submitted: 2017-01-09 21:42 UTC Modified: 2017-04-04 19:50 UTC
From: rossa dot milan at gmail dot com Assigned: nikic (profile)
Status: Closed Package: SPL related
PHP Version: 7.* OS: ALL
Private report: No CVE-ID: None
 [2017-01-09 21:42 UTC] rossa dot milan at gmail dot com
Use After Free in unserialize() with SplFixedArray. It is possible to leak memory and create gadgets to gain full memory read/write access. Demo of memory leak in script bellow.

Test script:
for ($i=0; $i<1000; $i++)
$z[$i] = str_repeat('A', 10);

$s = 'O:13:"SplFixedArray":2:{i:0;s:10:"1234567890";i:1;r:2;}';
$o = unserialize($s);
$b = &$o[1];
$o[1] = 0xbaad;

for ($i=0; $i<4000; $i++) {

Expected result:

Actual result:


Add a Patch

Pull Requests

Add a Pull Request


AllCommentsChangesGit/SVN commitsRelated reports
 [2017-01-12 12:01 UTC] rossa dot milan at gmail dot com
-PHP Version: 7.1.0 +PHP Version: 7.*
 [2017-01-12 12:01 UTC] rossa dot milan at gmail dot com
Also tested on 7.0.14 with success.
 [2017-01-16 07:54 UTC]
-Assigned To: +Assigned To: nikic
 [2017-01-16 07:54 UTC]
Nikita, could you take a look? Looks like both elements of SplFixedArray point to the same str, but it is freed prematurely instead of being separated when assignment is made. The refcount is correct 2 when leaving unserialize but then is decreased to 1 in ZEND_FETCH_DIM_W_SPEC_CV_CONST_HANDLER.
 [2017-03-30 20:29 UTC]
The use of unserialize() here is a red herring -- what is actually causing the memory errors is the attempt to acquire a reference into the SplFixedArray. A reduced reproduce script is the following (run under valgrind):

$a = new stdClass;
$b = new SplFixedArray(1);
$b[0] = $a;
$c = &$b[0];

As such, I do not believe this qualifies as a security issue under The issue cannot be triggered through user input. Instead, what triggers the issue is specific and atypical local code, namely the "$c = &$b[0]" line (it is atypical because ArrayAccess objects do not support references).

I believe the cause of this issue is the code at, which seems to assume that result is already in retval (which happens to be the case for non-internal implementations of offsetGet()).
 [2017-03-30 20:42 UTC]
Here is a patch against master which fixes the issue:
 [2017-03-31 23:57 UTC]
If it's not related to unserialize I assume it's not a security issue?
 [2017-04-02 11:56 UTC]
Stas - the reverse is actually true :)
(if it's related to unserialize, then it's not a security issue!)
 [2017-04-03 21:11 UTC]
Well, in both cases it requires specially crafted code, so unless I hear objections soon I will reclassify it.
 [2017-04-04 19:50 UTC]
-Type: Security +Type: Bug
 [2017-06-25 17:49 UTC]
Automatic comment on behalf of
Log: Fixed bug #73900
 [2017-06-25 17:49 UTC]
-Status: Assigned +Status: Closed
PHP Copyright © 2001-2018 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC