Merge pull request #20208 from geoffw0/sqlmodels

Rust: Fill some gaps in our database models.
This commit is contained in:
Geoffrey White
2025-08-13 08:54:23 +01:00
committed by GitHub
8 changed files with 53 additions and 6 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added more detail to models of `postgres`, `rusqlite`, `sqlx` and `tokio-postgres`. This may improve query results, particularly for `rust/sql-injection` and `rust/cleartext-storage-database`.

View File

@@ -13,3 +13,12 @@ extensions:
- ["<postgres::client::Client>::query_raw", "Argument[0]", "sql-injection", "manual"]
- ["<postgres::client::Client>::query_typed", "Argument[0]", "sql-injection", "manual"]
- ["<postgres::client::Client>::query_typed_raw", "Argument[0]", "sql-injection", "manual"]
- ["<postgres::client::Client>::simple_query", "Argument[0]", "sql-injection", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sourceModel
data:
- ["<postgres::row::Row>::get", "ReturnValue", "database", "manual"]
- ["<postgres::row::Row>::try_get", "ReturnValue.Field[core::result::Result::Ok(0)]", "database", "manual"]
- ["<postgres::row::SimpleQueryRow>::get", "ReturnValue.Field[core::option::Option::Some(0)]", "database", "manual"]
- ["<postgres::row::SimpleQueryRow>::try_get", "ReturnValue.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]", "database", "manual"]

View File

@@ -5,10 +5,12 @@ extensions:
data:
- ["<rusqlite::Connection>::execute", "Argument[0]", "sql-injection", "manual"]
- ["<rusqlite::Connection>::execute_batch", "Argument[0]", "sql-injection", "manual"]
- ["<rusqlite::Connection>::prepare_cached", "Argument[0]", "sql-injection", "manual"]
- ["<rusqlite::Connection>::prepare", "Argument[0]", "sql-injection", "manual"]
- [<rusqlite::Connection>::prepare_with_flags", "Argument[0]", "sql-injection", "manual"]
- ["<rusqlite::Connection>::prepare_with_flags", "Argument[0]", "sql-injection", "manual"]
- ["<rusqlite::Connection>::query_row", "Argument[0]", "sql-injection", "manual"]
- ["<rusqlite::Connection>::query_row_and_then", "Argument[0]", "sql-injection", "manual"]
- ["<rusqlite::Connection>::query_one", "Argument[0]", "sql-injection", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sourceModel

View File

@@ -11,3 +11,11 @@ extensions:
- ["sqlx_core::query_scalar_with::query_scalar_with", "Argument[0]", "sql-injection", "manual"]
- ["sqlx_core::raw_sql::raw_sql", "Argument[0]", "sql-injection", "manual"]
- ["<_ as sqlx_core::executor::Executor>::execute", "Argument[0]", "sql-injection", "manual"]
- addsTo:
pack: codeql/rust-all
extensible: sourceModel
data:
- ["<sqlx_core::row::Row>::get", "ReturnValue", "database", "manual"]
- ["<sqlx_core::row::Row>::get_unchecked", "ReturnValue", "database", "manual"]
- ["<sqlx_core::row::Row>::try_get", "ReturnValue.Field[core::result::Result::Ok(0)]", "database", "manual"]
- ["<sqlx_core::row::Row>::try_get_unchecked", "ReturnValue.Field[core::result::Result::Ok(0)]", "database", "manual"]

View File

@@ -9,6 +9,7 @@ extensions:
- ["<tokio_postgres::client::Client>::prepare", "Argument[0]", "sql-injection", "manual"]
- ["<tokio_postgres::client::Client>::prepare_typed", "Argument[0]", "sql-injection", "manual"]
- ["<tokio_postgres::client::Client>::query", "Argument[0]", "sql-injection", "manual"]
- ["<tokio_postgres::client::Client>::query_one", "Argument[0]", "sql-injection", "manual"]
- ["<tokio_postgres::client::Client>::query_opt", "Argument[0]", "sql-injection", "manual"]
- ["<tokio_postgres::client::Client>::query_raw", "Argument[0]", "sql-injection", "manual"]
- ["<tokio_postgres::client::Client>::query_typed", "Argument[0]", "sql-injection", "manual"]
@@ -21,3 +22,5 @@ extensions:
data:
- ["<tokio_postgres::row::Row>::get", "ReturnValue", "database", "manual"]
- ["<tokio_postgres::row::Row>::try_get", "ReturnValue.Field[core::result::Result::Ok(0)]", "database", "manual"]
- ["<tokio_postgres::row::SimpleQueryRow>::get", "ReturnValue.Field[core::option::Option::Some(0)]", "database", "manual"]
- ["<tokio_postgres::row::SimpleQueryRow>::try_get", "ReturnValue.Field[core::result::Result::Ok(0)].Field[core::option::Option::Some(0)]", "database", "manual"]

View File

@@ -5,3 +5,5 @@ multipleCallTargets
| main.rs:28:16:28:29 | query.as_str() |
| main.rs:29:20:29:33 | query.as_str() |
| main.rs:30:20:30:33 | query.as_str() |
| main.rs:32:20:32:33 | query.as_str() |
| main.rs:33:22:33:35 | query.as_str() |

View File

@@ -1,5 +1,4 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Get input from CLI
let args: Vec<String> = std::env::args().collect();
@@ -18,19 +17,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
)?;
let query = format!("INSERT INTO person (name, age) VALUES ('{}', '{}')", name, age);
let query2 = "INSERT INTO person (id) VALUES ($1)";
conn.execute(query.as_str(), &[])?; // $ sql-sink
conn.batch_execute(query.as_str())?; // $ sql-sink
conn.prepare(query.as_str())?; // $ sql-sink
// conn.prepare_typed(query.as_str(), &[])?;
conn.prepare_typed(query2, &[postgres::types::Type::INT4])?; // $ sql-sink
conn.query(query.as_str(), &[])?; // $ sql-sink
conn.query_one(query.as_str(), &[])?; // $ sql-sink
conn.query_opt(query.as_str(), &[])?; // $ sql-sink
// conn.query_raw(query.as_str(), &[])?;
// conn.query_typed(query.as_str(), &[])?;
// conn.query_typed_raw(query.as_str(), &[])?;
let params: Vec<i32> = vec![0];
conn.query_raw(query.as_str(), params)?; // $ sql-sink
conn.query_typed(query.as_str(), &[])?; // $ sql-sink
let params: Vec<(i32, postgres::types::Type)> = vec![(0, postgres::types::Type::INT4)];
conn.query_typed_raw(query2, params)?; // $ sql-sink
for row in &conn.query("SELECT id, name, age FROM person", &[])? { // $ sql-sink
let id: i32 = row.get("id"); // $ database-read
@@ -39,5 +41,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("found person: {} {} {}", id, name, age);
}
for message in &conn.simple_query("SELECT id, name, age FROM person")? { // $ sql-sink
if let postgres::SimpleQueryMessage::Row(row) = message {
let id: i32 = row.get(0).unwrap().parse().unwrap(); // $ database-read
let name: &str = row.get(1).unwrap(); // $ database-read
let age: i32 = row.get(2).unwrap().parse().unwrap(); // $ database-read
println!("found person: {} {} {}", id, name, age);
}
}
Ok(())
}

View File

@@ -48,5 +48,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
})
})?;
_ = connection.prepare_cached("SELECT id, name, age FROM person")?; // $ sql-sink
_ = connection.prepare_with_flags("SELECT id, name, age FROM person", rusqlite::PrepFlags::empty())?; // $ sql-sink
_ = connection.query_row_and_then("SELECT id, name, age FROM person", [], |row| { // $ sql-sink
let row: &rusqlite::Row<'_> = row;
let result: Result<i32, rusqlite::Error> = Ok(row.get(0)?); // $ database-read
result
})?;
Ok(())
}