-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
I have found these related issues/pull requests
N/A
Description
sqlx-sqlite currently builds SqliteError.message from sqlite3_errmsg() using str::from_utf8_unchecked():
let message = unsafe {
let msg = sqlite3_errmsg(handle);
debug_assert!(!msg.is_null());
str::from_utf8_unchecked(CStr::from_ptr(msg).to_bytes()).to_owned()
};That assumption is not valid for sqlite3_errmsg(). SQLite documents that if schema element names contain invalid UTF, error messages generated through sqlite3_errmsg() may also be invalid UTF.
Because SQLx exposes the result as a Rust String / &str, this is a safe-API soundness issue: a malicious or corrupted SQLite file can cause SQLx to construct an invalid Rust string.
This is distinct from the sqlite3_errstr() path in from_code(): SQLite documents sqlite3_errstr() as UTF-8, so the problem is specifically the sqlite3_errmsg() path.
Reproduction steps
Run the following SQL with any SQLite client (Python example included below):
CREATE TABLE t(x);
PRAGMA writable_schema = ON;
INSERT INTO sqlite_schema(type, name, tbl_name, rootpage, sql)
VALUES (
'view',
CAST(X'626164FF76696577' AS TEXT),
CAST(X'626164FF76696577' AS TEXT),
0,
'CREATE VIEW whatever AS SELECT FROM t'
);Python helper:
import sqlite3
con = sqlite3.connect("bad.db")
cur = con.cursor()
cur.execute("CREATE TABLE t(x)")
cur.execute("PRAGMA writable_schema=ON")
cur.execute(
"""
INSERT INTO sqlite_schema(type, name, tbl_name, rootpage, sql)
VALUES (
'view',
CAST(X'626164FF76696577' AS TEXT),
CAST(X'626164FF76696577' AS TEXT),
0,
'CREATE VIEW whatever AS SELECT FROM t'
)
"""
)
con.commit()
con.close()Step 2: Trigger the error through safe SQLx code
use sqlx::{Connection, sqlite::SqliteConnection};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut conn = SqliteConnection::connect("sqlite://bad.db").await?;
// Any schema-dependent statement is enough.
let err = sqlx::query("SELECT * FROM t")
.execute(&mut conn)
.await
.unwrap_err();
// On an affected build, this path is already UB because SQLx may have
// created an invalid Rust string from sqlite3_errmsg().
eprintln!("{err}");
Ok(())
}For comparison, a direct sqlite3_exec("SELECT * FROM t") on the crafted DB returns an error message whose raw bytes include 0xff:
malformed database schema (bad\xffview) - near "FROM": syntax error
SQLx version
main branch
Enabled SQLx features
default
Database server and version
SQLite
Operating system
MacOS
Rust version
1.94.0 (4a4ef493e 2026-03-02)