Skip to content

Commit afc2282

Browse files
andrewnesternikic
authored andcommitted
Fixed #74699 - Broken ArrayIterator unserializing
1 parent 51cdd3d commit afc2282

File tree

4 files changed

+147
-52
lines changed

4 files changed

+147
-52
lines changed

NEWS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? 2017 PHP 7.0.23
44

5-
5+
- SPL:
6+
. Fixed bug #74669 (Unserialize ArrayIterator broken). (Andrew Nester)
67

78
03 Aug 2017 PHP 7.0.22
89

ext/spl/spl_array.c

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,13 +1734,14 @@ SPL_METHOD(Array, serialize)
17341734
*/
17351735
SPL_METHOD(Array, unserialize)
17361736
{
1737-
spl_array_object *intern = Z_SPLARRAY_P(getThis());
1737+
zval *object = getThis();
1738+
spl_array_object *intern = Z_SPLARRAY_P(object);
17381739

17391740
char *buf;
17401741
size_t buf_len;
17411742
const unsigned char *p, *s;
17421743
php_unserialize_data_t var_hash;
1743-
zval *members, *zflags;
1744+
zval *members, *zflags, *array;
17441745
zend_long flags;
17451746

17461747
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &buf, &buf_len) == FAILURE) {
@@ -1782,24 +1783,38 @@ SPL_METHOD(Array, unserialize)
17821783
}
17831784
++p;
17841785

1785-
if (*p!='m') {
1786+
if (flags & SPL_ARRAY_IS_SELF) {
1787+
/* If IS_SELF is used, the flags are not followed by an array/object */
1788+
intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
1789+
intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
1790+
zval_ptr_dtor(&intern->array);
1791+
ZVAL_UNDEF(&intern->array);
1792+
} else {
17861793
if (*p!='a' && *p!='O' && *p!='C' && *p!='r') {
17871794
goto outexcept;
17881795
}
1796+
1797+
array = var_tmp_var(&var_hash);
1798+
if (!php_var_unserialize(array, &p, s + buf_len, &var_hash)
1799+
|| (Z_TYPE_P(array) != IS_ARRAY && Z_TYPE_P(array) != IS_OBJECT)) {
1800+
goto outexcept;
1801+
}
1802+
17891803
intern->ar_flags &= ~SPL_ARRAY_CLONE_MASK;
17901804
intern->ar_flags |= flags & SPL_ARRAY_CLONE_MASK;
1791-
zval_ptr_dtor(&intern->array);
1792-
ZVAL_UNDEF(&intern->array);
1793-
if (!php_var_unserialize(&intern->array, &p, s + buf_len, &var_hash)
1794-
|| (Z_TYPE(intern->array) != IS_ARRAY && Z_TYPE(intern->array) != IS_OBJECT)) {
1805+
1806+
if (Z_TYPE_P(array) == IS_ARRAY) {
1807+
zval_ptr_dtor(&intern->array);
1808+
ZVAL_COPY(&intern->array, array);
1809+
} else {
1810+
spl_array_set_array(object, intern, array, 0L, 1);
1811+
}
1812+
1813+
if (*p != ';') {
17951814
goto outexcept;
17961815
}
1797-
var_push_dtor(&var_hash, &intern->array);
1798-
}
1799-
if (*p != ';') {
1800-
goto outexcept;
1816+
++p;
18011817
}
1802-
++p;
18031818

18041819
/* members */
18051820
if (*p!= 'm' || *++p != ':') {

ext/spl/tests/bug70155.phpt

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,43 +8,10 @@ $data = unserialize($exploit);
88

99
var_dump($data);
1010
?>
11-
===DONE===
1211
--EXPECTF--
13-
object(ArrayObject)#1 (2) {
14-
[0]=>
15-
int(0)
16-
["storage":"ArrayObject":private]=>
17-
object(DateInterval)#2 (15) {
18-
["y"]=>
19-
int(3)
20-
["m"]=>
21-
int(-1)
22-
["d"]=>
23-
int(-1)
24-
["h"]=>
25-
int(-1)
26-
["i"]=>
27-
int(-1)
28-
["s"]=>
29-
int(-1)
30-
["weekday"]=>
31-
int(-1)
32-
["weekday_behavior"]=>
33-
int(-1)
34-
["first_last_day_of"]=>
35-
int(-1)
36-
["invert"]=>
37-
int(0)
38-
["days"]=>
39-
int(-1)
40-
["special_type"]=>
41-
int(0)
42-
["special_amount"]=>
43-
int(-1)
44-
["have_weekday_relative"]=>
45-
int(0)
46-
["have_special_relative"]=>
47-
int(0)
48-
}
49-
}
50-
===DONE===
12+
Fatal error: Uncaught InvalidArgumentException: Overloaded object of type DateInterval is not compatible with ArrayObject in %s
13+
Stack trace:
14+
%s
15+
%s
16+
%s
17+
%s

ext/spl/tests/bug74669.phpt

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
--TEST--
2+
Bug #74669: Unserialize ArrayIterator broken
3+
--FILE--
4+
<?php
5+
6+
class Container implements Iterator
7+
{
8+
public $container;
9+
public $iterator;
10+
11+
public function __construct()
12+
{
13+
$this->container = new ArrayObject();
14+
$this->iterator = $this->container->getIterator();
15+
}
16+
17+
public function append($element)
18+
{
19+
$this->container->append($element);
20+
}
21+
22+
public function current()
23+
{
24+
return $this->iterator->current();
25+
}
26+
27+
public function next()
28+
{
29+
$this->iterator->next();
30+
}
31+
32+
public function key()
33+
{
34+
return $this->iterator->key();
35+
}
36+
37+
public function valid()
38+
{
39+
return $this->iterator->valid();
40+
}
41+
42+
public function rewind()
43+
{
44+
$this->iterator->rewind();
45+
}
46+
}
47+
48+
class SelfArray extends ArrayObject
49+
{
50+
public function __construct()
51+
{
52+
parent::__construct($this);
53+
}
54+
}
55+
56+
$container = new Container();
57+
$container->append('test1');
58+
$container->append('test2');
59+
$container->valid();
60+
$serialized = serialize($container);
61+
unset($container);
62+
63+
$container = unserialize($serialized);
64+
65+
foreach ($container as $key => $value) {
66+
echo $key . ' => ' . $value . PHP_EOL;
67+
}
68+
69+
$arObj = new ArrayObject(['test1', 'test2']);
70+
$serialized = serialize($container);
71+
unset($arObj);
72+
73+
$arObj = unserialize($serialized);
74+
foreach($arObj as $key => $value) {
75+
echo $key . ' => ' . $value . PHP_EOL;
76+
}
77+
78+
$payload = 'x:i:33554432;O:8:"stdClass":0:{};m:a:0:{}';
79+
$str = 'C:11:"ArrayObject":' . strlen($payload) . ':{' . $payload . '}';
80+
81+
$ao = unserialize($str);
82+
var_dump($ao['foo']);
83+
84+
$selfArray = new SelfArray();
85+
$selfArray['foo'] = 'bar';
86+
var_dump($selfArray);
87+
$serialized = serialize($selfArray);
88+
var_dump($serialized);
89+
unset($selfArray);
90+
$selfArray = unserialize($serialized);
91+
var_dump($selfArray);
92+
var_dump($selfArray['foo']);
93+
94+
?>
95+
--EXPECTF--
96+
0 => test1
97+
1 => test2
98+
0 => test1
99+
1 => test2
100+
101+
Notice: Undefined index: foo in %s on line %s
102+
NULL
103+
object(SelfArray)#9 (1) {
104+
["foo"]=>
105+
string(3) "bar"
106+
}
107+
string(62) "C:9:"SelfArray":41:{x:i:16777216;m:a:1:{s:3:"foo";s:3:"bar";}}"
108+
object(SelfArray)#9 (1) {
109+
["foo"]=>
110+
string(3) "bar"
111+
}
112+
string(3) "bar"

0 commit comments

Comments
 (0)