Skip to content

Commit 7ddd441

Browse files
committed
Rust: Split off sources/database test.
1 parent 81132be commit 7ddd441

File tree

9 files changed

+2505
-216
lines changed

9 files changed

+2505
-216
lines changed

rust/ql/test/library-tests/dataflow/sources/database/Cargo.lock

Lines changed: 2008 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/ql/test/library-tests/dataflow/sources/database/InlineFlow.expected

Lines changed: 205 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* @kind path-problem
3+
*/
4+
5+
import rust
6+
import codeql.rust.dataflow.DataFlow
7+
import codeql.rust.Concepts
8+
import utils.test.InlineFlowTest
9+
10+
/**
11+
* Configuration for flow from any threat model source to an argument of the function `sink`.
12+
*/
13+
module MyFlowConfig implements DataFlow::ConfigSig {
14+
predicate isSource(DataFlow::Node source) { source instanceof ThreatModelSource }
15+
16+
predicate isSink(DataFlow::Node sink) {
17+
any(CallExpr call |
18+
call.getFunction().(PathExpr).getPath().getSegment().getIdentifier().getText() = "sink"
19+
).getArgList().getAnArg() = sink.asExpr().getExpr()
20+
}
21+
22+
predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
23+
// flow out from any content at the sink.
24+
isSink(node) and
25+
exists(c)
26+
}
27+
}
28+
29+
module MyFlowTest = TaintFlowTest<MyFlowConfig>;
30+
31+
import MyFlowTest
32+
import PathGraph
33+
34+
from PathNode source, PathNode sink
35+
where flowPath(source, sink)
36+
select sink, source, sink, "$@", source, source.toString()
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
| test.rs:15:47:15:51 | query | Flow source 'DatabaseSource' of type database (DEFAULT). |
2+
| test.rs:18:28:18:30 | get | Flow source 'DatabaseSource' of type database (DEFAULT). |
3+
| test.rs:21:28:21:34 | get_opt | Flow source 'DatabaseSource' of type database (DEFAULT). |
4+
| test.rs:24:28:24:31 | take | Flow source 'DatabaseSource' of type database (DEFAULT). |
5+
| test.rs:27:28:27:35 | take_opt | Flow source 'DatabaseSource' of type database (DEFAULT). |
6+
| test.rs:30:26:30:31 | as_ref | Flow source 'DatabaseSource' of type database (DEFAULT). |
7+
| test.rs:37:28:37:38 | query_first | Flow source 'DatabaseSource' of type database (DEFAULT). |
8+
| test.rs:40:27:40:35 | exec_iter | Flow source 'DatabaseSource' of type database (DEFAULT). |
9+
| test.rs:41:42:41:44 | get | Flow source 'DatabaseSource' of type database (DEFAULT). |
10+
| test.rs:48:22:48:30 | query_map | Flow source 'DatabaseSource' of type database (DEFAULT). |
11+
| test.rs:55:22:55:30 | query_map | Flow source 'DatabaseSource' of type database (DEFAULT). |
12+
| test.rs:64:26:64:35 | query_fold | Flow source 'DatabaseSource' of type database (DEFAULT). |
13+
| test.rs:70:22:70:31 | query_fold | Flow source 'DatabaseSource' of type database (DEFAULT). |
14+
| test.rs:102:53:102:57 | query | Flow source 'DatabaseSource' of type database (DEFAULT). |
15+
| test.rs:105:28:105:30 | get | Flow source 'DatabaseSource' of type database (DEFAULT). |
16+
| test.rs:108:28:108:34 | get_opt | Flow source 'DatabaseSource' of type database (DEFAULT). |
17+
| test.rs:111:28:111:31 | take | Flow source 'DatabaseSource' of type database (DEFAULT). |
18+
| test.rs:114:28:114:35 | take_opt | Flow source 'DatabaseSource' of type database (DEFAULT). |
19+
| test.rs:117:26:117:31 | as_ref | Flow source 'DatabaseSource' of type database (DEFAULT). |
20+
| test.rs:124:28:124:38 | query_first | Flow source 'DatabaseSource' of type database (DEFAULT). |
21+
| test.rs:127:27:127:35 | exec_iter | Flow source 'DatabaseSource' of type database (DEFAULT). |
22+
| test.rs:135:22:135:30 | query_map | Flow source 'DatabaseSource' of type database (DEFAULT). |
23+
| test.rs:142:22:142:30 | query_map | Flow source 'DatabaseSource' of type database (DEFAULT). |
24+
| test.rs:151:26:151:35 | query_fold | Flow source 'DatabaseSource' of type database (DEFAULT). |
25+
| test.rs:157:22:157:31 | query_fold | Flow source 'DatabaseSource' of type database (DEFAULT). |
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
query: queries/summary/TaintSources.ql
2+
postprocess: utils/test/InlineExpectationsTestQuery.ql
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
qltest_cargo_check: true
2+
qltest_dependencies:
3+
- async-std = { version = "1.13.1" }
4+
- futures = { version = "0.3" }
5+
- mysql = { version = "26.0.1" }
6+
- mysql_async = { version = "0.36.1" }
7+
- tokio = { version = "1.43.0", features = ["full"] }
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
fn sink<T>(_: T) { }
2+
3+
// --- tests ---
4+
5+
mod test_mysql {
6+
use mysql::*;
7+
use mysql::prelude::*;
8+
use super::sink;
9+
10+
pub fn test_mysql() -> Result<(), Box<dyn std::error::Error>> {
11+
// connect through a MySQL connection pool
12+
let mut pool = mysql::Pool::new("")?;
13+
let mut conn = pool.get_conn()?;
14+
15+
let mut rows : Vec<mysql::Row> = conn.query("SELECT id, name, age FROM person")?; // $ Alert[rust/summary/taint-sources]
16+
let mut row = &mut rows[0];
17+
18+
let v1 : i64 = row.get(0).unwrap(); // $ Alert[rust/summary/taint-sources]
19+
sink(v1); // $ hasTaintFlow=0
20+
21+
let v2 : i64 = row.get_opt(0).unwrap().unwrap(); // $ Alert[rust/summary/taint-sources]
22+
sink(v2); // $ hasTaintFlow=0
23+
24+
let v3 : i64 = row.take(0).unwrap(); // $ Alert[rust/summary/taint-sources]
25+
sink(v3); // $ hasTaintFlow=0
26+
27+
let v4 : i64 = row.take_opt(0).unwrap().unwrap(); // $ Alert[rust/summary/taint-sources]
28+
sink(v4); // $ hasTaintFlow=0
29+
30+
let value5 = row.as_ref(0).unwrap(); // $ Alert[rust/summary/taint-sources]
31+
if let mysql::Value::Int(v) = value5 {
32+
sink(v); // $ MISSING: hasTaintFlow=0
33+
} else if let mysql::Value::Bytes(v) = value5 {
34+
sink(v); // $ MISSING: hasTaintFlow=0
35+
}
36+
37+
let v6: i64 = conn.query_first("SELECT id FROM person")?.unwrap(); // $ Alert[rust/summary/taint-sources]
38+
sink(v6); // $ hasTaintFlow
39+
40+
let mut t1 = conn.exec_iter("SELECT id FROM person", (1, 2, 3))?; // $ Alert[rust/summary/taint-sources]
41+
sink(t1.nth(0).unwrap().unwrap().get::<i64, usize>(1).unwrap()); // $ Alert[rust/summary/taint-sources] hasTaintFlow=1
42+
for row in t1 {
43+
for v in row {
44+
sink(v); // $ hasTaintFlow
45+
}
46+
}
47+
48+
let _ = conn.query_map( // $ Alert[rust/summary/taint-sources]
49+
"SELECT id FROM person",
50+
|values: i64| -> () {
51+
sink(values); // $ hasTaintFlow
52+
}
53+
)?;
54+
55+
let _ = conn.query_map( // $ Alert[rust/summary/taint-sources]
56+
"SELECT id, name, age FROM person",
57+
|values: (i64, String, i32)| -> () {
58+
sink(values.0); // $ MISSING: hasTaintFlow
59+
sink(values.1); // $ MISSING: hasTaintFlow
60+
sink(values.2); // $ MISSING: hasTaintFlow
61+
}
62+
)?;
63+
64+
let total = conn.query_fold("SELECT id FROM person", 0, |acc: i64, row: i64| { // $ Alert[rust/summary/taint-sources]
65+
sink(row); // $ hasTaintFlow
66+
acc + row
67+
})?;
68+
sink(total); // $ hasTaintFlow
69+
70+
let _ = conn.query_fold("SELECT id, name, age FROM person", 0, |acc: i64, row: (i64, String, i32)| { // $ Alert[rust/summary/taint-sources]
71+
let id: i64 = row.0;
72+
let name: String = row.1;
73+
let age: i32 = row.2;
74+
sink(id); // $ MISSING: hasTaintFlow
75+
sink(name); // $ MISSING: hasTaintFlow
76+
sink(age); // $ MISSING: hasTaintFlow
77+
acc + 1
78+
})?;
79+
80+
Ok(())
81+
}
82+
}
83+
84+
mod test_mysql_async {
85+
use mysql_async::*;
86+
use mysql_async::prelude::*;
87+
use async_std::stream::StreamExt;
88+
use super::sink;
89+
90+
#[derive(Debug, PartialEq, Eq, Clone)]
91+
struct Person {
92+
id: i64,
93+
name: String,
94+
age: i32,
95+
}
96+
97+
pub async fn test_mysql_async() -> Result<()> {
98+
// connect through a MySQL connection pool
99+
let mut pool = mysql_async::Pool::new("");
100+
let mut conn = pool.get_conn().await?;
101+
102+
let mut rows : Vec<mysql_async::Row> = conn.query("SELECT id, name, age FROM person").await?; // $ Alert[rust/summary/taint-sources]
103+
let mut row = &mut rows[0];
104+
105+
let v1 : i64 = row.get(0).unwrap(); // $ Alert[rust/summary/taint-sources]
106+
sink(v1); // $ hasTaintFlow=0
107+
108+
let v2 : i64 = row.get_opt(0).unwrap().unwrap(); // $ Alert[rust/summary/taint-sources]
109+
sink(v2); // $ hasTaintFlow=0
110+
111+
let v3 : i64 = row.take(0).unwrap(); // $ Alert[rust/summary/taint-sources]
112+
sink(v3); // $ hasTaintFlow=0
113+
114+
let v4 : i64 = row.take_opt(0).unwrap().unwrap(); // $ Alert[rust/summary/taint-sources]
115+
sink(v4); // $ hasTaintFlow=0
116+
117+
let value5 = row.as_ref(0).unwrap(); // $ Alert[rust/summary/taint-sources]
118+
if let mysql_async::Value::Int(v) = value5 {
119+
sink(v); // $ MISSING: hasTaintFlow=0
120+
} else if let mysql_async::Value::Bytes(v) = value5 {
121+
sink(v); // $ MISSING: hasTaintFlow=0
122+
}
123+
124+
let v6: i64 = conn.query_first("SELECT id FROM person").await?.unwrap(); // $ Alert[rust/summary/taint-sources]
125+
sink(v6); // $ MISSING: hasTaintFlow
126+
127+
let mut t1 = conn.exec_iter("SELECT id FROM person", (1, 2, 3)).await?; // $ Alert[rust/summary/taint-sources]
128+
for mut row in t1.stream::<(i64, String, i32)>().await? {
129+
while let v = row.next().await {
130+
let v = v.unwrap();
131+
sink(v); // $ MISSING: hasTaintFlow
132+
}
133+
}
134+
135+
let _ = conn.query_map( // $ Alert[rust/summary/taint-sources]
136+
"SELECT id FROM person",
137+
|values: i64| -> () {
138+
sink(values); // $ hasTaintFlow
139+
}
140+
).await?;
141+
142+
let _ = conn.query_map( // $ Alert[rust/summary/taint-sources]
143+
"SELECT id, name, age FROM person",
144+
|values: (i64, String, i32)| -> () {
145+
sink(values.0); // $ MISSING: hasTaintFlow
146+
sink(values.1); // $ MISSING: hasTaintFlow
147+
sink(values.2); // $ MISSING: hasTaintFlow
148+
}
149+
).await?;
150+
151+
let total = conn.query_fold("SELECT id FROM person", 0, |acc: i64, row: i64| { // $ Alert[rust/summary/taint-sources]
152+
sink(row); // $ hasTaintFlow
153+
acc + row
154+
}).await?;
155+
sink(total); // $ hasTaintFlow
156+
157+
let _ = conn.query_fold("SELECT id, name, age FROM person", 0, |acc: i64, row: (i64, String, i32)| { // $ Alert[rust/summary/taint-sources]
158+
let id: i64 = row.0;
159+
let name: String = row.1;
160+
let age: i32 = row.2;
161+
sink(id); // $ MISSING: hasTaintFlow
162+
sink(name); // $ MISSING: hasTaintFlow
163+
sink(age); // $ MISSING: hasTaintFlow
164+
acc + 1
165+
}).await?;
166+
167+
let ids = "SELECT id FROM person".with(()).map(&mut conn,
168+
|person: i64| -> i64 {
169+
sink(person); // $ MISSING: hasTaintFlow
170+
person
171+
}
172+
).await?;
173+
sink(ids[0]); // $ MISSING: hasTaintFlow
174+
175+
let ages = "SELECT id, name, age FROM person".with(()).map(&mut conn, // $ MISSING: Alert[rust/summary/taint-sources]
176+
|person: (i64, String, i32)| -> i32 {
177+
sink(person.0); // $ MISSING: hasTaintFlow
178+
sink(person.1); // $ MISSING: hasTaintFlow
179+
sink(person.2); // $ MISSING: hasTaintFlow
180+
person.2
181+
}
182+
).await?;
183+
sink(ages[0]); // $ MISSING: hasTaintFlow
184+
185+
{
186+
let mut stream = "SELECT id FROM person".stream::<i64, _>(&mut conn).await?; // $ MISSING: Alert[rust/summary/taint-sources]
187+
while let Some(row) = stream.next().await {
188+
let id = row?;
189+
sink(id); // $ MISSING: hasTaintFlow
190+
}
191+
}
192+
193+
{
194+
let mut stream = "SELECT id, name, age FROM person".stream::<(i64, String, i32), _>(&mut conn).await?; // $ MISSING: Alert[rust/summary/taint-sources]
195+
while let Some(row) = stream.next().await {
196+
let (id, name, age) = row?;
197+
sink(id); // $ MISSING: hasTaintFlow
198+
sink(name); // $ MISSING: hasTaintFlow
199+
sink(age); // $ MISSING: hasTaintFlow
200+
}
201+
}
202+
203+
Ok(())
204+
}
205+
}
206+
207+
#[tokio::main]
208+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
209+
println!("test_mysql...");
210+
match test_mysql::test_mysql() {
211+
Ok(_) => println!("complete"),
212+
Err(e) => println!("error: {}", e),
213+
}
214+
215+
println!("test_mysql_async...");
216+
match futures::executor::block_on(test_mysql_async::test_mysql_async()) {
217+
Ok(_) => println!("complete"),
218+
Err(e) => println!("error: {}", e),
219+
}
220+
221+
Ok(())
222+
}

rust/ql/test/library-tests/dataflow/sources/options.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,3 @@ qltest_dependencies:
1616
- futures-rustls = { version = "0.26.0" }
1717
- async-std = { version = "1.13.1" }
1818
- warp = { version = "0.4.2", features = ["server"] }
19-
- mysql = { version = "26.0.1" }
20-
- mysql_async = { version = "0.36.1" }

0 commit comments

Comments
 (0)