From 8ed21a89f30cb4a7575c8232c0946d50416a74bd Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Mon, 18 Jul 2022 17:33:34 +0200 Subject: [PATCH] Fix GH-9032: SQLite3 authorizer crashes on NULL values The arguments 3 to 6 of the authorizer callback may be `NULL`[1], and we have to properly deal with that. Instead of causing a segfault, we deny authorization, which is still better than a crash, and apparently, we cannot do better anyway. [1] Closes GH-9040. --- NEWS | 6 ++++++ ext/pdo_sqlite/sqlite_driver.c | 7 +++++-- ext/pdo_sqlite/tests/gh9032.phpt | 26 ++++++++++++++++++++++++++ ext/sqlite3/sqlite3.c | 3 +++ ext/sqlite3/tests/gh9032.phpt | 28 ++++++++++++++++++++++++++++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 ext/pdo_sqlite/tests/gh9032.phpt create mode 100644 ext/sqlite3/tests/gh9032.phpt diff --git a/NEWS b/NEWS index cd184fb879d..e63742c4412 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,12 @@ PHP NEWS . Fixed bug GH-9033 (Loading blacklist file can fail due to negative length). (cmb) +- PDO_SQLite: + . Fixed bug GH-9032 (SQLite3 authorizer crashes on NULL values). (cmb) + +- SQLite3: + . Fixed bug GH-9032 (SQLite3 authorizer crashes on NULL values). (cmb) + - Standard: . Fixed bug GH-9017 (php_stream_sock_open_from_socket could return NULL). (Heiko Weber) diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 26fa1c00eb8..4233ff10ff2 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -715,6 +715,9 @@ static const struct pdo_dbh_methods sqlite_methods = { static char *make_filename_safe(const char *filename) { + if (!filename) { + return NULL; + } if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) { char *fullpath = expand_filepath(filename, NULL); @@ -737,7 +740,7 @@ static int authorizer(void *autharg, int access_type, const char *arg3, const ch char *filename; switch (access_type) { case SQLITE_COPY: { - filename = make_filename_safe(arg4); + filename = make_filename_safe(arg4); if (!filename) { return SQLITE_DENY; } @@ -746,7 +749,7 @@ static int authorizer(void *autharg, int access_type, const char *arg3, const ch } case SQLITE_ATTACH: { - filename = make_filename_safe(arg3); + filename = make_filename_safe(arg3); if (!filename) { return SQLITE_DENY; } diff --git a/ext/pdo_sqlite/tests/gh9032.phpt b/ext/pdo_sqlite/tests/gh9032.phpt new file mode 100644 index 00000000000..f96b06d1d85 --- /dev/null +++ b/ext/pdo_sqlite/tests/gh9032.phpt @@ -0,0 +1,26 @@ +--TEST-- +SQLite3 authorizer crashes on NULL values +--SKIPIF-- + +--INI-- +open_basedir=. +--FILE-- + PDO::ERRMODE_EXCEPTION]); + +$db->exec('attach database \':memory:\' AS "db1"'); +var_dump($db->exec('create table db1.r (id int)')); + +try { +$st = $db->prepare('attach database :a AS "db2"'); +$st->execute([':a' => ':memory:']); +var_dump($db->exec('create table db2.r (id int)')); +} catch (PDOException $ex) { + echo $ex->getMessage(), PHP_EOL; +} +?> +--EXPECT-- +int(0) +SQLSTATE[HY000]: General error: 23 not authorized diff --git a/ext/sqlite3/sqlite3.c b/ext/sqlite3/sqlite3.c index cd91e68fd3e..80257328f9f 100644 --- a/ext/sqlite3/sqlite3.c +++ b/ext/sqlite3/sqlite3.c @@ -2049,6 +2049,9 @@ static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, c /* Check open_basedir restrictions first */ if (PG(open_basedir) && *PG(open_basedir)) { if (action == SQLITE_ATTACH) { + if (!arg1) { + return SQLITE_DENY; + } if (memcmp(arg1, ":memory:", sizeof(":memory:")) && *arg1) { if (strncmp(arg1, "file:", 5) == 0) { /* starts with "file:" */ diff --git a/ext/sqlite3/tests/gh9032.phpt b/ext/sqlite3/tests/gh9032.phpt new file mode 100644 index 00000000000..2494d4cb6ba --- /dev/null +++ b/ext/sqlite3/tests/gh9032.phpt @@ -0,0 +1,28 @@ +--TEST-- +SQLite3 authorizer crashes on NULL values +--SKIPIF-- + +--INI-- +open_basedir=. +--FILE-- +enableExceptions(true); + +$db->exec('attach database \':memory:\' AS "db1"'); +var_dump($db->exec('create table db1.r (id int)')); + +try { + $st = $db->prepare('attach database :a AS "db2"'); + $st->bindValue("a", ":memory:"); + $st->execute(); + var_dump($db->exec('create table db2.r (id int)')); +} catch (Exception $ex) { + echo $ex->getMessage(), PHP_EOL; +} +?> +--EXPECT-- +bool(true) +Unable to prepare statement: 23, not authorized