diff --git a/rust/ql/lib/codeql/rust/frameworks/postgres.model.yml b/rust/ql/lib/codeql/rust/frameworks/postgres.model.yml new file mode 100644 index 000000000000..c877947a45f4 --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/postgres.model.yml @@ -0,0 +1,15 @@ +extensions: + - addsTo: + pack: codeql/rust-all + extensible: sinkModel + data: + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::execute", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::batch_execute", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::prepare", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::prepare_typed", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::query", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::query_one", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::query_opt", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::query_raw", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::query_typed", "Argument[0]", "sql-injection", "manual"] + - ["repo:https://github.com/sfackler/rust-postgres:postgres", "::query_typed_raw", "Argument[0]", "sql-injection", "manual"] diff --git a/rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected b/rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected index b2b6872a6d25..d9cf909c792c 100644 --- a/rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected +++ b/rust/ql/test/library-tests/dataflow/taint/TaintFlowStep.expected @@ -1,6 +1,6 @@ -| file://:0:0:0:0 | [summary param] 0 in lang:alloc::_::crate::fmt::format | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::crate::fmt::format | MaD:14 | -| file://:0:0:0:0 | [summary param] self in lang:alloc::_::::as_str | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::as_str | MaD:12 | -| file://:0:0:0:0 | [summary param] self in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | file://:0:0:0:0 | [summary] to write: ReturnValue.Variant[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | MaD:0 | +| file://:0:0:0:0 | [summary param] 0 in lang:alloc::_::crate::fmt::format | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::crate::fmt::format | MaD:24 | +| file://:0:0:0:0 | [summary param] self in lang:alloc::_::::as_str | file://:0:0:0:0 | [summary] to write: ReturnValue in lang:alloc::_::::as_str | MaD:22 | +| file://:0:0:0:0 | [summary param] self in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | file://:0:0:0:0 | [summary] to write: ReturnValue.Variant[crate::result::Result::Ok(0)] in repo:https://github.com/seanmonstar/reqwest:reqwest::_::::text | MaD:10 | | main.rs:4:5:4:8 | 1000 | main.rs:4:5:4:12 | ... + ... | | | main.rs:4:12:4:12 | i | main.rs:4:5:4:12 | ... + ... | | | main.rs:8:20:8:20 | s | main.rs:8:14:8:20 | FormatArgsExpr | | diff --git a/rust/ql/test/library-tests/frameworks/postgres/Postgres.expected b/rust/ql/test/library-tests/frameworks/postgres/Postgres.expected new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/rust/ql/test/library-tests/frameworks/postgres/Postgres.ql b/rust/ql/test/library-tests/frameworks/postgres/Postgres.ql new file mode 100644 index 000000000000..4681fee505f5 --- /dev/null +++ b/rust/ql/test/library-tests/frameworks/postgres/Postgres.ql @@ -0,0 +1,19 @@ +import rust +import codeql.rust.security.SqlInjectionExtensions +import utils.test.InlineExpectationsTest + +module PostgresTest implements TestSig { + string getARelevantTag() { result = "sql-sink" } + + predicate hasActualResult(Location location, string element, string tag, string value) { + exists(SqlInjection::Sink sink | + location = sink.getLocation() and + location.getFile().getBaseName() != "" and + element = sink.toString() and + tag = "sql-sink" and + value = "" + ) + } +} + +import MakeTest diff --git a/rust/ql/test/library-tests/frameworks/postgres/cargo.toml.manual b/rust/ql/test/library-tests/frameworks/postgres/cargo.toml.manual new file mode 100644 index 000000000000..8c6b2d9e5a72 --- /dev/null +++ b/rust/ql/test/library-tests/frameworks/postgres/cargo.toml.manual @@ -0,0 +1,13 @@ +[workspace] + +[package] +name = "postgres-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +postgres = { version = "0.19" } + +[[bin]] +name = "postgres" +path = "./main.rs" diff --git a/rust/ql/test/library-tests/frameworks/postgres/main.rs b/rust/ql/test/library-tests/frameworks/postgres/main.rs new file mode 100644 index 000000000000..5754ef427824 --- /dev/null +++ b/rust/ql/test/library-tests/frameworks/postgres/main.rs @@ -0,0 +1,43 @@ + + +fn main() -> Result<(), Box> { + // Get input from CLI + let args: Vec = std::env::args().collect(); + let name = &args[1]; + let age = &args[2]; + + let mut conn = postgres::Client::connect("host=localhost user=postgres", postgres::NoTls)?; + + conn.execute( // $ sql-sink + "CREATE TABLE person ( + id SERIAL PRIMARY KEY, + name VARCHAR NOT NULL, + age INT NOT NULL + )", + &[], + )?; + + let query = format!("INSERT INTO person (name, age) VALUES ('{}', '{}')", name, age); + + 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.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(), &[])?; + + for row in &conn.query("SELECT id, name, age FROM person", &[])? { // $ sql-sink + let id: i32 = row.get("id"); + let name: &str = row.get("name"); + let age: i32 = row.get("age"); + println!("found person: {} {} {}", id, name, age); + } + + Ok(()) +} \ No newline at end of file diff --git a/rust/ql/test/library-tests/frameworks/postgres/options.yml b/rust/ql/test/library-tests/frameworks/postgres/options.yml new file mode 100644 index 000000000000..27f6588af263 --- /dev/null +++ b/rust/ql/test/library-tests/frameworks/postgres/options.yml @@ -0,0 +1,3 @@ +qltest_cargo_check: true +qltest_dependencies: + - postgres = { version = "0.19" }