diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 7cd8880b86099..5a4d7b583f16c 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -224,8 +224,27 @@ static zend_string* sqlite_handle_quoter(pdo_dbh_t *dbh, const zend_string *unqu { char *quoted; if (ZSTR_LEN(unquoted) > (INT_MAX - 3) / 2) { + php_error_docref(NULL, E_WARNING, "String is too long to be quoted"); return NULL; } + // check if it contains a null byte + if (memchr(ZSTR_VAL(unquoted), '\0', ZSTR_LEN(unquoted))) { + if(((ZSTR_LEN(unquoted) * 2) + 3) > (INT_MAX - 3) / 2) { + php_error_docref(NULL, E_WARNING, "Binary string is too long to be quoted"); + return NULL; + } + zend_string *quoted_str = zend_string_alloc((ZSTR_LEN(unquoted) * 2) + 4, 0); // 4: x'hex'\x00 + // x'hex' + quoted_str->val[0] = 'x'; + quoted_str->val[1] = '\''; + for (size_t i = 0; i < ZSTR_LEN(unquoted); i++) { + sprintf(quoted_str->val + 2 + (i * 2), "%02x", (unsigned char)ZSTR_VAL(unquoted)[i]); + } + quoted_str->val[2 + (ZSTR_LEN(unquoted) * 2)] = '\''; + quoted_str->val[3 + (ZSTR_LEN(unquoted) * 2)] = '\0'; + quoted_str->len = (ZSTR_LEN(unquoted) * 2) + 3; + return quoted_str; + } quoted = safe_emalloc(2, ZSTR_LEN(unquoted), 3); /* TODO use %Q format? */ sqlite3_snprintf(2*ZSTR_LEN(unquoted) + 3, quoted, "'%q'", ZSTR_VAL(unquoted)); diff --git a/ext/pdo_sqlite/tests/bug81740.phpt b/ext/pdo_sqlite/tests/bug81740.phpt index 2b8b9447f0fed..1dc5a8aca9194 100644 --- a/ext/pdo_sqlite/tests/bug81740.phpt +++ b/ext/pdo_sqlite/tests/bug81740.phpt @@ -16,5 +16,6 @@ $pdo = new PDO("sqlite::memory:"); $string = str_repeat("a", 0x80000000); var_dump($pdo->quote($string)); ?> ---EXPECT-- +--EXPECTF-- +Warning: PDO::quote(): String is too long to be quoted in %s on line %d bool(false) diff --git a/ext/pdo_sqlite/tests/bug_gh13952_quote_null.phpt b/ext/pdo_sqlite/tests/bug_gh13952_quote_null.phpt new file mode 100644 index 0000000000000..29b57575b2d86 --- /dev/null +++ b/ext/pdo_sqlite/tests/bug_gh13952_quote_null.phpt @@ -0,0 +1,12 @@ +--TEST-- +Bug #GH-13952 (sqlite PDO::quote silently corrupts strings with null bytes) +--EXTENSIONS-- +pdo +pdo_sqlite +--FILE-- + PDO::ERRMODE_EXCEPTION]); +var_dump($pdo->query("SELECT " . $pdo->quote("foo\x00bar"))->fetch(PDO::FETCH_NUM)[0] === "foo\x00bar"); +?> +--EXPECT-- +bool(true)