Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Fix #97836 and #81705: Segfault / type confusion in concat_function
The following sequence of actions was happening which caused a null pointer dereference: 1. debug_backtrace() returns an array 2. The concatenation to $c will transform the array to a string via `zval_get_string_func` for op2 and output a warning. Note that zval op1 is of type string due to the first do-while sequence. 3. The warning of an implicit "array to string conversion" triggers the ob_start callback to run. This code transform $c (==op1) to a long. 4. The code below the 2 do-while sequences assume that both op1 and op2 are strings, but this is no longer the case. A dereference of the string will therefore result in a null pointer dereference. The solution used here is to work with the zend_string directly instead of with the ops. For the tests: Co-authored-by: changochen1@gmail.com Co-authored-by: cmbecker69@gmx.de Co-authored-by: yukik@risec.co.jp Closes GH-10049.
- Loading branch information
Showing
8 changed files
with
198 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
--TEST-- | ||
Bug #79836 (Segfault in concat_function) | ||
--INI-- | ||
opcache.optimization_level = 0x7FFEBFFF & ~0x400 | ||
--FILE-- | ||
<?php | ||
$counter = 0; | ||
ob_start(function ($buffer) use (&$c, &$counter) { | ||
$c = 0; | ||
++$counter; | ||
}, 1); | ||
$c .= []; | ||
$c .= []; | ||
ob_end_clean(); | ||
echo $counter . "\n"; | ||
?> | ||
--EXPECT-- | ||
3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
--TEST-- | ||
Bug #79836 (Segfault in concat_function) | ||
--INI-- | ||
opcache.optimization_level = 0x7FFEBFFF & ~0x400 | ||
--FILE-- | ||
<?php | ||
$x = 'non-empty'; | ||
ob_start(function () use (&$c) { | ||
$c = 0; | ||
}, 1); | ||
$c = []; | ||
$x = $c . $x; | ||
$x = $c . $x; | ||
ob_end_clean(); | ||
echo "Done\n"; | ||
?> | ||
--EXPECT-- | ||
Done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
--TEST-- | ||
Bug #79836 (Segfault in concat_function) | ||
--FILE-- | ||
<?php | ||
$c = str_repeat("abcd", 10); | ||
|
||
ob_start(function () use (&$c) { | ||
$c = 0; | ||
}, 1); | ||
|
||
class X { | ||
function __toString() { | ||
echo "a"; | ||
return "abc"; | ||
} | ||
} | ||
|
||
$xxx = new X; | ||
|
||
$x = $c . $xxx; | ||
ob_end_clean(); | ||
echo $x . "\n"; | ||
?> | ||
--EXPECT-- | ||
abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
--TEST-- | ||
Bug #81705 (type confusion/UAF on set_error_handler with concat operation) | ||
--FILE-- | ||
<?php | ||
|
||
$arr = [0]; | ||
$my_var = str_repeat("a", 1); | ||
set_error_handler( | ||
function() use(&$my_var) { | ||
echo("error\n"); | ||
$my_var = 0x123; | ||
} | ||
); | ||
$my_var .= $GLOBALS["arr"]; | ||
var_dump($my_var); | ||
?> | ||
--EXPECT-- | ||
error | ||
string(6) "aArray" |
21 changes: 21 additions & 0 deletions
21
Zend/tests/class_toString_concat_non_interned_with_itself.phpt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--TEST-- | ||
Test concatenating a class instance that has __toString with itself that uses a non-interned string | ||
--FILE-- | ||
<?php | ||
$global_non_interned_string = str_repeat("a", 3); | ||
|
||
class Test { | ||
public function __toString() { | ||
global $global_non_interned_string; | ||
return $global_non_interned_string; | ||
} | ||
} | ||
|
||
$test1 = new Test; | ||
$test2 = new Test; | ||
$test1 .= $test2; | ||
|
||
echo $test1 . "\n"; | ||
?> | ||
--EXPECT-- | ||
aaaaaa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
--TEST-- | ||
Test concatenating a class instance that has __toString with itself | ||
--FILE-- | ||
<?php | ||
class Tmp { | ||
public function __toString() { | ||
return "abc"; | ||
} | ||
} | ||
|
||
$tmp = new Tmp; | ||
$tmp .= $tmp; | ||
echo $tmp . "\n"; | ||
?> | ||
--EXPECT-- | ||
abcabc |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
727e26f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this commit may lead to incorrect behavior. Produce non-string return value.
php -r '$a = false; $a .= $a; var_dump($a);'
This may cause the followingviolation of the type inference and the following crash in JIT.
See oss-fuzz #59184
727e26f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another problem caused by the same patch is 59072
The following script casuses use-after-free after a memory overflow
727e26f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CC @iluuu1994
727e26f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dstogov Thanks, I'll have a look.
727e26f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, There is exploit based on this bug, which works on versions PHP 8.0.29, 8.1.20 and already unsupported 7.3.33, 7.4.33:
https://raw.githubusercontent.com/mm0r1/exploits/master/php-concat-bypass/exploit.php
How it could be fixed?