-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* PHP-8.4: ext/pdo: Fix a UAF when changing default fetch class ctor args
- Loading branch information
Showing
7 changed files
with
421 additions
and
1 deletion.
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
59 changes: 59 additions & 0 deletions
59
ext/pdo/tests/pdo_fetch_class_change_ctor_args_during_fetch1.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,59 @@ | ||
--TEST-- | ||
PDO Common: PDO::FETCH_CLASS with a constructor that changes the ctor args within PDO::fetch() | ||
--EXTENSIONS-- | ||
pdo | ||
--SKIPIF-- | ||
<?php | ||
$dir = getenv('REDIR_TEST_DIR'); | ||
if (false == $dir) die('skip no driver'); | ||
require_once $dir . 'pdo_test.inc'; | ||
PDOTest::skip(); | ||
?> | ||
--FILE-- | ||
<?php | ||
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/'); | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
|
||
class Test { | ||
public string $val1; | ||
public string $val2; | ||
|
||
public function __construct(mixed $v) { | ||
var_dump($v); | ||
if ($v instanceof PDOStatement) { | ||
$v->setFetchMode(PDO::FETCH_CLASS, 'Test', [$this->val2]); | ||
} | ||
} | ||
} | ||
|
||
$db->exec('CREATE TABLE pdo_fetch_class_change_ctor_one(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10))'); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_one VALUES(1, 'A', 'alpha')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_one VALUES(2, 'B', 'beta')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_one VALUES(3, 'C', 'gamma')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_one VALUES(4, 'D', 'delta')"); | ||
|
||
$stmt = $db->prepare('SELECT val1, val2 FROM pdo_fetch_class_change_ctor_one'); | ||
$stmt->setFetchMode(PDO::FETCH_CLASS, 'Test', [$stmt]); | ||
|
||
$stmt->execute(); | ||
var_dump($stmt->fetch()); | ||
|
||
?> | ||
--CLEAN-- | ||
<?php | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
PDOTest::dropTableIfExists($db, "pdo_fetch_class_change_ctor_one"); | ||
?> | ||
--EXPECTF-- | ||
object(PDOStatement)#%d (1) { | ||
["queryString"]=> | ||
string(54) "SELECT val1, val2 FROM pdo_fetch_class_change_ctor_one" | ||
} | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "A" | ||
["val2"]=> | ||
string(5) "alpha" | ||
} |
59 changes: 59 additions & 0 deletions
59
ext/pdo/tests/pdo_fetch_class_change_ctor_args_during_fetch2.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,59 @@ | ||
--TEST-- | ||
PDO Common: PDO::FETCH_CLASS with a constructor that changes the ctor args within PDO::fetchObject() | ||
--EXTENSIONS-- | ||
pdo | ||
--SKIPIF-- | ||
<?php | ||
$dir = getenv('REDIR_TEST_DIR'); | ||
if (false == $dir) die('skip no driver'); | ||
require_once $dir . 'pdo_test.inc'; | ||
PDOTest::skip(); | ||
?> | ||
--FILE-- | ||
<?php | ||
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/'); | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
|
||
class Test { | ||
public string $val1; | ||
public string $val2; | ||
|
||
public function __construct(mixed $v) { | ||
var_dump($v); | ||
if ($v instanceof PDOStatement) { | ||
$v->setFetchMode(PDO::FETCH_CLASS, 'Test', [$this->val2]); | ||
} | ||
} | ||
} | ||
|
||
// TODO Rename pdo_fetch_class_change_ctor_two table to pdo_fetch_class_change_ctor_two in PHP-8.4 | ||
$db->exec('CREATE TABLE pdo_fetch_class_change_ctor_two(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10))'); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_two VALUES(1, 'A', 'alpha')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_two VALUES(2, 'B', 'beta')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_two VALUES(3, 'C', 'gamma')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_two VALUES(4, 'D', 'delta')"); | ||
|
||
$stmt = $db->prepare('SELECT val1, val2 FROM pdo_fetch_class_change_ctor_two'); | ||
|
||
$stmt->execute(); | ||
var_dump($stmt->fetchObject('Test', [$stmt])); | ||
|
||
?> | ||
--CLEAN-- | ||
<?php | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
PDOTest::dropTableIfExists($db, "pdo_fetch_class_change_ctor_two"); | ||
?> | ||
--EXPECTF-- | ||
object(PDOStatement)#%s (1) { | ||
["queryString"]=> | ||
string(54) "SELECT val1, val2 FROM pdo_fetch_class_change_ctor_two" | ||
} | ||
object(Test)#%s (2) { | ||
["val1"]=> | ||
string(1) "A" | ||
["val2"]=> | ||
string(5) "alpha" | ||
} |
86 changes: 86 additions & 0 deletions
86
ext/pdo/tests/pdo_fetch_class_change_ctor_args_during_fetch3.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,86 @@ | ||
--TEST-- | ||
PDO Common: PDO::FETCH_CLASS with a constructor that changes the ctor args within PDO::fetchAll() (no args variation) | ||
--EXTENSIONS-- | ||
pdo | ||
--SKIPIF-- | ||
<?php | ||
$dir = getenv('REDIR_TEST_DIR'); | ||
if (false == $dir) die('skip no driver'); | ||
require_once $dir . 'pdo_test.inc'; | ||
PDOTest::skip(); | ||
?> | ||
--FILE-- | ||
<?php | ||
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/'); | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
|
||
class Test { | ||
public string $val1; | ||
public string $val2; | ||
|
||
public function __construct(mixed $v) { | ||
var_dump($v); | ||
if ($v instanceof PDOStatement) { | ||
$v->setFetchMode(PDO::FETCH_CLASS, 'Test', [$this->val2]); | ||
} | ||
} | ||
} | ||
|
||
$db->exec('CREATE TABLE pdo_fetch_class_change_ctor_three(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10))'); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_three VALUES(1, 'A', 'alpha')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_three VALUES(2, 'B', 'beta')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_three VALUES(3, 'C', 'gamma')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_three VALUES(4, 'D', 'delta')"); | ||
|
||
$stmt = $db->prepare('SELECT val1, val2 FROM pdo_fetch_class_change_ctor_three'); | ||
$stmt->setFetchMode(PDO::FETCH_CLASS, 'Test', [$stmt]); | ||
|
||
$stmt->execute(); | ||
var_dump($stmt->fetchAll()); | ||
|
||
?> | ||
--CLEAN-- | ||
<?php | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
PDOTest::dropTableIfExists($db, "pdo_fetch_class_change_ctor_three"); | ||
?> | ||
--EXPECTF-- | ||
object(PDOStatement)#%d (1) { | ||
["queryString"]=> | ||
string(56) "SELECT val1, val2 FROM pdo_fetch_class_change_ctor_three" | ||
} | ||
string(5) "alpha" | ||
string(5) "alpha" | ||
string(5) "alpha" | ||
array(4) { | ||
[0]=> | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "A" | ||
["val2"]=> | ||
string(5) "alpha" | ||
} | ||
[1]=> | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "B" | ||
["val2"]=> | ||
string(4) "beta" | ||
} | ||
[2]=> | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "C" | ||
["val2"]=> | ||
string(5) "gamma" | ||
} | ||
[3]=> | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "D" | ||
["val2"]=> | ||
string(5) "delta" | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
ext/pdo/tests/pdo_fetch_class_change_ctor_args_during_fetch4.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,85 @@ | ||
--TEST-- | ||
PDO Common: PDO::FETCH_CLASS with a constructor that changes the ctor args within PDO::fetchAll() (args in fetchAll) | ||
--EXTENSIONS-- | ||
pdo | ||
--SKIPIF-- | ||
<?php | ||
$dir = getenv('REDIR_TEST_DIR'); | ||
if (false == $dir) die('skip no driver'); | ||
require_once $dir . 'pdo_test.inc'; | ||
PDOTest::skip(); | ||
?> | ||
--FILE-- | ||
<?php | ||
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/'); | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
|
||
class Test { | ||
public string $val1; | ||
public string $val2; | ||
|
||
public function __construct(mixed $v) { | ||
var_dump($v); | ||
if ($v instanceof PDOStatement) { | ||
$v->setFetchMode(PDO::FETCH_CLASS, 'Test', [$this->val2]); | ||
} | ||
} | ||
} | ||
|
||
$db->exec('CREATE TABLE pdo_fetch_class_change_ctor_four(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10))'); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_four VALUES(1, 'A', 'alpha')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_four VALUES(2, 'B', 'beta')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_four VALUES(3, 'C', 'gamma')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_four VALUES(4, 'D', 'delta')"); | ||
|
||
$stmt = $db->prepare('SELECT val1, val2 FROM pdo_fetch_class_change_ctor_four'); | ||
|
||
$stmt->execute(); | ||
var_dump($stmt->fetchAll(PDO::FETCH_CLASS, 'Test', [$stmt])); | ||
|
||
?> | ||
--CLEAN-- | ||
<?php | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
PDOTest::dropTableIfExists($db, "pdo_fetch_class_change_ctor_four"); | ||
?> | ||
--EXPECTF-- | ||
object(PDOStatement)#%d (1) { | ||
["queryString"]=> | ||
string(55) "SELECT val1, val2 FROM pdo_fetch_class_change_ctor_four" | ||
} | ||
string(5) "alpha" | ||
string(5) "alpha" | ||
string(5) "alpha" | ||
array(4) { | ||
[0]=> | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "A" | ||
["val2"]=> | ||
string(5) "alpha" | ||
} | ||
[1]=> | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "B" | ||
["val2"]=> | ||
string(4) "beta" | ||
} | ||
[2]=> | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "C" | ||
["val2"]=> | ||
string(5) "gamma" | ||
} | ||
[3]=> | ||
object(Test)#%d (2) { | ||
["val1"]=> | ||
string(1) "D" | ||
["val2"]=> | ||
string(5) "delta" | ||
} | ||
} |
55 changes: 55 additions & 0 deletions
55
ext/pdo/tests/pdo_fetch_class_change_ctor_args_during_fetch5.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,55 @@ | ||
--TEST-- | ||
PDO Common: PDO::FETCH_CLASS with a constructor that changes the ctor args within PDO::fetchAll() (via warning and error handler) | ||
--EXTENSIONS-- | ||
pdo | ||
--SKIPIF-- | ||
<?php | ||
$dir = getenv('REDIR_TEST_DIR'); | ||
if (false == $dir) die('skip no driver'); | ||
require_once $dir . 'pdo_test.inc'; | ||
PDOTest::skip(); | ||
?> | ||
--FILE-- | ||
<?php | ||
if (getenv('REDIR_TEST_DIR') === false) putenv('REDIR_TEST_DIR='.__DIR__ . '/../../pdo/tests/'); | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
|
||
// Warning to hook into error handler | ||
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING); | ||
|
||
class B { | ||
public function __construct() {} | ||
} | ||
|
||
$db->exec('CREATE TABLE pdo_fetch_class_change_ctor_five(id int NOT NULL PRIMARY KEY, val1 VARCHAR(10), val2 VARCHAR(10))'); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_five VALUES(1, 'A', 'alpha')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_five VALUES(2, 'B', 'beta')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_five VALUES(3, 'C', 'gamma')"); | ||
$db->exec("INSERT INTO pdo_fetch_class_change_ctor_five VALUES(4, 'D', 'delta')"); | ||
|
||
$stmt = $db->prepare('SELECT val1, val2 FROM pdo_fetch_class_change_ctor_five'); | ||
$stmt->execute(); | ||
|
||
function stuffingErrorHandler(int $errno, string $errstr, string $errfile, int $errline) { | ||
global $stmt; | ||
$stmt->setFetchMode(PDO::FETCH_CLASS, 'B', [$errstr]); | ||
echo $errstr, PHP_EOL; | ||
} | ||
set_error_handler(stuffingErrorHandler(...)); | ||
|
||
var_dump($stmt->fetchAll(PDO::FETCH_CLASS|PDO::FETCH_SERIALIZE, 'B', [$stmt])); | ||
|
||
?> | ||
--CLEAN-- | ||
<?php | ||
require_once getenv('REDIR_TEST_DIR') . 'pdo_test.inc'; | ||
$db = PDOTest::factory(); | ||
PDOTest::dropTableIfExists($db, "pdo_fetch_class_change_ctor_five"); | ||
?> | ||
--EXPECTF-- | ||
PDOStatement::fetchAll(): The PDO::FETCH_SERIALIZE mode is deprecated | ||
PDOStatement::fetchAll(): SQLSTATE[HY000]: General error: cannot unserialize class | ||
PDOStatement::fetchAll(): SQLSTATE[HY000]: General error%S | ||
array(0) { | ||
} |
Oops, something went wrong.