Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ext/pdo_sqlite/sqlite_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ static char *make_filename_safe(const char *filename)
}
return estrdup(filename);
}
if (*filename && strcmp(filename, ":memory:")) {
if (*filename && strncmp(filename, ":memory:", sizeof(":memory:")-1) != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this 100% safe and wouldn't be something like :memory:/path processed like regular filepath?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this is not only theoretical, but also the real reason why the CI is failing - a file (instead of in-memory DB) is created.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The official condition is in https://github.com/sqlite/sqlite/blob/version-3.50.4/src/btree.c#L2552.

I even wonder what is :memory:?cache=shared, I did not find any testcase for it in Sqlite codebase.

Copy link

@AnrDaemon AnrDaemon Oct 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "cache" connection parameter lets you specify the "shared key" to connect to in-memory database created in a different process.
Ref: https://www.sqlite.org/inmemorydb.html#sharedmemdb

The value could be anything, on production we're using UUID generated at deploy time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The interesting point is that it works on Linux (tested multiple times)

PHP Version 8.4.5
Linux 1bb44a69f3cb 4.18.0-553.el8_10.x86_64 #1 SMP Fri May 24 13:05:10 UTC 2024 x86_64
PDO Driver for SQLite 3.x enabled
SQLite Library 3.48.0

char *fullpath = expand_filepath(filename, NULL);

if (!fullpath) {
Expand Down
13 changes: 13 additions & 0 deletions ext/pdo_sqlite/tests/gh20076.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
GH-20076 (open_basedir prohibits opening :memory:?cache=shared)
--EXTENSIONS--
sqlite3
--INI--
open_basedir=xx
--FILE--
<?php
var_dump(new PDO("sqlite::memory:?cache=shared"));
?>
--EXPECT--
object(PDO)#1 (0) {
}
4 changes: 2 additions & 2 deletions ext/sqlite3/sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ PHP_METHOD(SQLite3, open)
RETURN_THROWS();
}

if (filename_len != 0 && (filename_len != sizeof(":memory:")-1 ||
if (filename_len != 0 && (filename_len < sizeof(":memory:")-1 ||
memcmp(filename, ":memory:", sizeof(":memory:")-1) != 0)) {
if (!(fullpath = expand_filepath(filename, NULL))) {
zend_throw_exception(zend_ce_exception, "Unable to expand filepath", 0);
Expand All @@ -126,7 +126,7 @@ PHP_METHOD(SQLite3, open)
RETURN_THROWS();
}
} else {
/* filename equals "" or ":memory:" */
/* filename equals "" or starts with ":memory:" */
fullpath = filename;
}

Expand Down
13 changes: 13 additions & 0 deletions ext/sqlite3/tests/gh20076.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
--TEST--
GH-20076 (open_basedir prohibits opening :memory:?cache=shared)
--EXTENSIONS--
sqlite3
--INI--
open_basedir=xx
--FILE--
<?php
var_dump(new SQLite3(":memory:?cache=shared"));
?>
--EXPECT--
object(SQLite3)#1 (0) {
}
Loading