Skip to content

Commit 71cbef7

Browse files
committed
Fixed bug #80111
Remove traverse_pointer before destroying the element contents.
1 parent 044de83 commit 71cbef7

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

ext/spl/spl_dllist.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -796,14 +796,14 @@ PHP_METHOD(SplDoublyLinkedList, offsetUnset)
796796
/* finally, delete the element */
797797
llist->count--;
798798

799-
zval_ptr_dtor(&element->data);
800-
ZVAL_UNDEF(&element->data);
801-
802799
if (intern->traverse_pointer == element) {
803800
SPL_LLIST_DELREF(element);
804801
intern->traverse_pointer = NULL;
805802
}
806803

804+
zval_ptr_dtor(&element->data);
805+
ZVAL_UNDEF(&element->data);
806+
807807
SPL_LLIST_DELREF(element);
808808
} else {
809809
zend_argument_error(spl_ce_OutOfRangeException, 1, "is an invalid offset");

ext/spl/tests/bug80111.phpt

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
--TEST--
2+
Bug #80111: PHP SplDoublyLinkedList::offsetUnset UAF Sandbox Escape
3+
--FILE--
4+
<?php
5+
6+
function i2s(&$s, $p, $i, $x=8)
7+
{
8+
for($j=0;$j<$x;$j++)
9+
{
10+
$s[$p+$j] = chr($i & 0xff);
11+
$i >>= 8;
12+
}
13+
}
14+
15+
class Trigger
16+
{
17+
function __destruct()
18+
{
19+
global $s, $b;
20+
# Add a reference afterwards
21+
//$v = new SplDoublyLinkedList();
22+
//$v->setIteratorMode(SplDoublyLinkedList::IT_MODE_DELETE);
23+
# Remove element #2 from the list: this has no effect on
24+
# intern->traverse_pointer, since it is removed from the list already
25+
# The element, along with the zval, is freed
26+
unset($s[0]);
27+
28+
$a = str_shuffle(str_repeat('A', 40-24-1));
29+
# Build a fake zval (long, value: 12345678)
30+
i2s($a, 0x00, 12345678); # ptr
31+
i2s($a, 0x08, 4, 7); # type: long
32+
33+
var_dump($s->current());
34+
$s->next();
35+
# The value is our fake zval
36+
var_dump($s->current());
37+
print_r('DONE'."\n");
38+
}
39+
}
40+
41+
# Create a 3-item dllist
42+
$s = new SplDoublyLinkedList();
43+
44+
# This is the UAF trigger
45+
$s->push(new Trigger());
46+
47+
#$b = &$a;
48+
$s->push(3);
49+
50+
# Points intern->traverse_pointer to our object element
51+
$s->rewind();
52+
#$s->next();
53+
54+
# calls SplDoublyLinkedList::offsetUnset, which will remove the element from the
55+
# dllist, and then destruct the object, before clearing traverse_pointer
56+
unset($s[0]);
57+
58+
?>
59+
--EXPECT--
60+
NULL
61+
NULL
62+
DONE

0 commit comments

Comments
 (0)