Skip to content

Commit 0300bfa

Browse files
nielsdosbon
authored andcommitted
Fix #81992: SplFixedArray::setSize() causes use-after-free
Upon resizing, the elements are destroyed from lower index to higher index. When an element refers to an object with a destructor, it can refer to a lower (i.e. already destroyed) element, causing a uaf. Set refcounted zvals to NULL after destroying them to avoid a uaf. Closes phpGH-11959.
1 parent 3c62183 commit 0300bfa

File tree

2 files changed

+98
-0
lines changed

2 files changed

+98
-0
lines changed

ext/spl/tests/bug81992.phpt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
Bug #81992 (SplFixedArray::setSize() causes use-after-free)
3+
--FILE--
4+
<?php
5+
class InvalidDestructor {
6+
public function __destruct() {
7+
global $obj;
8+
var_dump($obj[0]);
9+
try {
10+
var_dump($obj[2]);
11+
} catch (Throwable $e) {
12+
echo $e->getMessage(), "\n";
13+
}
14+
try {
15+
var_dump($obj[4]);
16+
} catch (Throwable $e) {
17+
echo $e->getMessage(), "\n";
18+
}
19+
}
20+
}
21+
22+
$obj = new SplFixedArray(5);
23+
$obj[0] = str_repeat("A", 10);
24+
$obj[2] = str_repeat('B', 10);
25+
$obj[3] = new InvalidDestructor();
26+
$obj[4] = str_repeat('C', 10);
27+
$obj->setSize(2);
28+
?>
29+
--EXPECT--
30+
string(10) "AAAAAAAAAA"
31+
Index invalid or out of range
32+
Index invalid or out of range

ext/spl/tests/bug81992b.phpt

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
--TEST--
2+
Bug #81992 (SplFixedArray::setSize() causes use-after-free) - setSize variation
3+
--FILE--
4+
<?php
5+
class InvalidDestructor {
6+
public function __construct(
7+
private int $desiredSize,
8+
private SplFixedArray $obj,
9+
) {}
10+
11+
public function __destruct() {
12+
echo "In destructor\n";
13+
$this->obj->setSize($this->desiredSize);
14+
echo "Destroyed, size is now still ", $this->obj->getSize(), "\n";
15+
}
16+
}
17+
18+
class DestructorLogger {
19+
public function __construct(private int $id) {}
20+
21+
public function __destruct() {
22+
echo "Destroyed the logger with id ", $this->id, "\n";
23+
}
24+
}
25+
26+
function test(int $desiredSize) {
27+
$obj = new SplFixedArray(5);
28+
$obj[0] = str_repeat("A", 10);
29+
$obj[1] = new DestructorLogger(1);
30+
$obj[2] = str_repeat('B', 10);
31+
$obj[3] = new InvalidDestructor($desiredSize, $obj);
32+
$obj[4] = new DestructorLogger(4);
33+
$obj->setSize(2);
34+
echo "Size is now ", $obj->getSize(), "\n";
35+
echo "Done\n";
36+
}
37+
38+
echo "--- Smaller size test ---\n";
39+
test(1);
40+
echo "--- Equal size test ---\n";
41+
test(2);
42+
echo "--- Larger size test ---\n";
43+
test(10);
44+
?>
45+
--EXPECT--
46+
--- Smaller size test ---
47+
In destructor
48+
Destroyed, size is now still 2
49+
Destroyed the logger with id 4
50+
Destroyed the logger with id 1
51+
Size is now 1
52+
Done
53+
--- Equal size test ---
54+
In destructor
55+
Destroyed, size is now still 2
56+
Destroyed the logger with id 4
57+
Size is now 2
58+
Done
59+
Destroyed the logger with id 1
60+
--- Larger size test ---
61+
In destructor
62+
Destroyed, size is now still 2
63+
Destroyed the logger with id 4
64+
Size is now 10
65+
Done
66+
Destroyed the logger with id 1

0 commit comments

Comments
 (0)