Skip to content

Commit bb02167

Browse files
committed
Add QL test
1 parent e458441 commit bb02167

File tree

6 files changed

+110
-0
lines changed

6 files changed

+110
-0
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#select
2+
| src/main.rs:10:5:10:22 | ...::read_to_string | src/main.rs:6:11:6:19 | file_name | src/main.rs:10:5:10:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:6:11:6:19 | file_name | user-provided value |
3+
| src/main.rs:22:5:22:22 | ...::read_to_string | src/main.rs:15:11:15:19 | file_name | src/main.rs:22:5:22:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:15:11:15:19 | file_name | user-provided value |
4+
| src/main.rs:35:5:35:22 | ...::read_to_string | src/main.rs:27:11:27:19 | file_path | src/main.rs:35:5:35:22 | ...::read_to_string | This path depends on a $@. | src/main.rs:27:11:27:19 | file_path | user-provided value |
5+
edges
6+
| src/main.rs:6:11:6:19 | file_name | src/main.rs:8:35:8:43 | file_name | provenance | |
7+
| src/main.rs:8:9:8:17 | file_path | src/main.rs:10:24:10:32 | file_path | provenance | |
8+
| src/main.rs:8:21:8:44 | ...::from(...) | src/main.rs:8:9:8:17 | file_path | provenance | |
9+
| src/main.rs:8:35:8:43 | file_name | src/main.rs:8:21:8:44 | ...::from(...) | provenance | MaD:3 |
10+
| src/main.rs:10:24:10:32 | file_path | src/main.rs:10:5:10:22 | ...::read_to_string | provenance | MaD:1 Sink:MaD:1 |
11+
| src/main.rs:15:11:15:19 | file_name | src/main.rs:21:35:21:43 | file_name | provenance | |
12+
| src/main.rs:21:9:21:17 | file_path | src/main.rs:22:24:22:32 | file_path | provenance | |
13+
| src/main.rs:21:21:21:44 | ...::from(...) | src/main.rs:21:9:21:17 | file_path | provenance | |
14+
| src/main.rs:21:35:21:43 | file_name | src/main.rs:21:21:21:44 | ...::from(...) | provenance | MaD:3 |
15+
| src/main.rs:22:24:22:32 | file_path | src/main.rs:22:5:22:22 | ...::read_to_string | provenance | MaD:1 Sink:MaD:1 |
16+
| src/main.rs:27:11:27:19 | file_path | src/main.rs:30:52:30:60 | file_path | provenance | |
17+
| src/main.rs:30:9:30:17 | file_path | src/main.rs:35:24:35:32 | file_path | provenance | |
18+
| src/main.rs:30:21:30:62 | public_path.join(...) | src/main.rs:30:9:30:17 | file_path | provenance | |
19+
| src/main.rs:30:38:30:61 | ...::from(...) | src/main.rs:30:21:30:62 | public_path.join(...) | provenance | MaD:2 |
20+
| src/main.rs:30:52:30:60 | file_path | src/main.rs:30:38:30:61 | ...::from(...) | provenance | MaD:3 |
21+
| src/main.rs:35:24:35:32 | file_path | src/main.rs:35:5:35:22 | ...::read_to_string | provenance | MaD:1 Sink:MaD:1 |
22+
models
23+
| 1 | Sink: lang:std; crate::fs::read_to_string; path-injection; Argument[0] |
24+
| 2 | Summary: lang:std; <crate::path::Path>::join; Argument[0]; ReturnValue; taint |
25+
| 3 | Summary: lang:std; <crate::path::PathBuf as crate::convert::From>::from; Argument[0]; ReturnValue; taint |
26+
nodes
27+
| src/main.rs:6:11:6:19 | file_name | semmle.label | file_name |
28+
| src/main.rs:8:9:8:17 | file_path | semmle.label | file_path |
29+
| src/main.rs:8:21:8:44 | ...::from(...) | semmle.label | ...::from(...) |
30+
| src/main.rs:8:35:8:43 | file_name | semmle.label | file_name |
31+
| src/main.rs:10:5:10:22 | ...::read_to_string | semmle.label | ...::read_to_string |
32+
| src/main.rs:10:24:10:32 | file_path | semmle.label | file_path |
33+
| src/main.rs:15:11:15:19 | file_name | semmle.label | file_name |
34+
| src/main.rs:21:9:21:17 | file_path | semmle.label | file_path |
35+
| src/main.rs:21:21:21:44 | ...::from(...) | semmle.label | ...::from(...) |
36+
| src/main.rs:21:35:21:43 | file_name | semmle.label | file_name |
37+
| src/main.rs:22:5:22:22 | ...::read_to_string | semmle.label | ...::read_to_string |
38+
| src/main.rs:22:24:22:32 | file_path | semmle.label | file_path |
39+
| src/main.rs:27:11:27:19 | file_path | semmle.label | file_path |
40+
| src/main.rs:30:9:30:17 | file_path | semmle.label | file_path |
41+
| src/main.rs:30:21:30:62 | public_path.join(...) | semmle.label | public_path.join(...) |
42+
| src/main.rs:30:38:30:61 | ...::from(...) | semmle.label | ...::from(...) |
43+
| src/main.rs:30:52:30:60 | file_path | semmle.label | file_path |
44+
| src/main.rs:35:5:35:22 | ...::read_to_string | semmle.label | ...::read_to_string |
45+
| src/main.rs:35:24:35:32 | file_path | semmle.label | file_path |
46+
subpaths
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
query: queries/security/CWE-022/TaintedPath.ql
2+
postprocess:
3+
- utils/test/PrettyPrintModels.ql
4+
- utils/test/InlineExpectationsTestQuery.ql

rust/ql/test/query-tests/security/CWE-022/TaintedPathSinks.expected

Whitespace-only changes.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import rust
2+
import codeql.rust.security.TaintedPathExtensions
3+
import utils.test.InlineExpectationsTest
4+
5+
module TaintedPathSinksTest implements TestSig {
6+
string getARelevantTag() { result = "path-injection-sink" }
7+
8+
predicate hasActualResult(Location location, string element, string tag, string value) {
9+
exists(TaintedPath::Sink sink |
10+
location = sink.getLocation() and
11+
location.getFile().getBaseName() != "" and
12+
element = sink.toString() and
13+
tag = "path-injection-sink" and
14+
value = ""
15+
)
16+
}
17+
}
18+
19+
import MakeTest<TaintedPathSinksTest>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
qltest_cargo_check: true
2+
qltest_dependencies:
3+
- poem = { version = "3.1.7" }
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use poem::{error::InternalServerError, handler, http::StatusCode, web::Query, Error, Result};
2+
use std::{env::home_dir, fs, path::PathBuf};
3+
4+
//#[handler]
5+
fn tainted_path_handler_bad(
6+
Query(file_name): Query<String>, // $ Source=remote1
7+
) -> Result<String> {
8+
let file_path = PathBuf::from(file_name);
9+
// BAD: This could read any file on the filesystem.
10+
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink Alert[rust/path-injection]=remote1
11+
}
12+
13+
//#[handler]
14+
fn tainted_path_handler_good(
15+
Query(file_name): Query<String>, // $ Source=remote2
16+
) -> Result<String> {
17+
// GOOD: ensure that the filename has no path separators or parent directory references
18+
if file_name.contains("..") || file_name.contains("/") || file_name.contains("\\") {
19+
return Err(Error::from_status(StatusCode::BAD_REQUEST));
20+
}
21+
let file_path = PathBuf::from(file_name);
22+
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink SPURIOUS: Alert[rust/path-injection]=remote2
23+
}
24+
25+
//#[handler]
26+
fn tainted_path_handler_folder_good(
27+
Query(file_path): Query<String>, // $ Source=remote3
28+
) -> Result<String> {
29+
let public_path = home_dir().unwrap().join("public");
30+
let file_path = public_path.join(PathBuf::from(file_path));
31+
// GOOD: ensure that the path stays within the public folder
32+
if !file_path.starts_with(public_path) {
33+
return Err(Error::from_status(StatusCode::BAD_REQUEST));
34+
}
35+
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink SPURIOUS: Alert[rust/path-injection]=remote3
36+
}
37+
38+
fn main() {}

0 commit comments

Comments
 (0)