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] <https://www.sqlite.org/c3ref/set_authorizer.html>

Closes GH-9040.
This commit is contained in:
Christoph M. Becker 2022-07-18 17:33:34 +02:00
parent a442e29485
commit 8ed21a89f3
No known key found for this signature in database
GPG key ID: D66C9593118BCCB6
5 changed files with 68 additions and 2 deletions

6
NEWS
View file

@ -11,6 +11,12 @@ PHP NEWS
. Fixed bug GH-9033 (Loading blacklist file can fail due to negative length). . Fixed bug GH-9033 (Loading blacklist file can fail due to negative length).
(cmb) (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: - Standard:
. Fixed bug GH-9017 (php_stream_sock_open_from_socket could return NULL). . Fixed bug GH-9017 (php_stream_sock_open_from_socket could return NULL).
(Heiko Weber) (Heiko Weber)

View file

@ -715,6 +715,9 @@ static const struct pdo_dbh_methods sqlite_methods = {
static char *make_filename_safe(const char *filename) static char *make_filename_safe(const char *filename)
{ {
if (!filename) {
return NULL;
}
if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) { if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) {
char *fullpath = expand_filepath(filename, NULL); 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; char *filename;
switch (access_type) { switch (access_type) {
case SQLITE_COPY: { case SQLITE_COPY: {
filename = make_filename_safe(arg4); filename = make_filename_safe(arg4);
if (!filename) { if (!filename) {
return SQLITE_DENY; return SQLITE_DENY;
} }
@ -746,7 +749,7 @@ static int authorizer(void *autharg, int access_type, const char *arg3, const ch
} }
case SQLITE_ATTACH: { case SQLITE_ATTACH: {
filename = make_filename_safe(arg3); filename = make_filename_safe(arg3);
if (!filename) { if (!filename) {
return SQLITE_DENY; return SQLITE_DENY;
} }

View file

@ -0,0 +1,26 @@
--TEST--
SQLite3 authorizer crashes on NULL values
--SKIPIF--
<?php
if (!extension_loaded("pdo_sqlite")) die("skip pdo_sqlite extension not available");
?>
--INI--
open_basedir=.
--FILE--
<?php
$db = new PDO("sqlite::memory:", null, null, [PDO::ATTR_ERRMODE => 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

View file

@ -2049,6 +2049,9 @@ static int php_sqlite3_authorizer(void *autharg, int action, const char *arg1, c
/* Check open_basedir restrictions first */ /* Check open_basedir restrictions first */
if (PG(open_basedir) && *PG(open_basedir)) { if (PG(open_basedir) && *PG(open_basedir)) {
if (action == SQLITE_ATTACH) { if (action == SQLITE_ATTACH) {
if (!arg1) {
return SQLITE_DENY;
}
if (memcmp(arg1, ":memory:", sizeof(":memory:")) && *arg1) { if (memcmp(arg1, ":memory:", sizeof(":memory:")) && *arg1) {
if (strncmp(arg1, "file:", 5) == 0) { if (strncmp(arg1, "file:", 5) == 0) {
/* starts with "file:" */ /* starts with "file:" */

View file

@ -0,0 +1,28 @@
--TEST--
SQLite3 authorizer crashes on NULL values
--SKIPIF--
<?php
if (!extension_loaded("sqlite3")) die("skip sqlite3 extension not available");
?>
--INI--
open_basedir=.
--FILE--
<?php
$db = new SQLite3(":memory:");
$db->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