Rust: Add tags to intermediate steps in the test.

This commit is contained in:
Geoffrey White
2025-08-14 11:37:22 +01:00
parent ecf0e08f55
commit 6941e7fef1
2 changed files with 48 additions and 9 deletions

View File

@@ -1,9 +1,18 @@
import rust
import codeql.rust.security.TaintedPathExtensions
import utils.test.InlineExpectationsTest
import codeql.rust.dataflow.DataFlow
import codeql.rust.dataflow.internal.DataFlowImpl as DataflowImpl
import codeql.rust.Concepts
module TaintedPathSinksTest implements TestSig {
string getARelevantTag() { result = "path-injection-sink" }
string getARelevantTag() {
result =
[
"path-injection-sink", "path-injection-barrier", "path-injection-normalize",
"path-injection-checked"
]
}
predicate hasActualResult(Location location, string element, string tag, string value) {
exists(TaintedPath::Sink sink |
@@ -13,6 +22,36 @@ module TaintedPathSinksTest implements TestSig {
tag = "path-injection-sink" and
value = ""
)
or
exists(DataFlow::Node node |
(
node instanceof TaintedPath::Barrier or
node instanceof TaintedPath::SanitizerGuard // tends to label the node *after* the check
) and
location = node.getLocation() and
location.getFile().getBaseName() != "" and
element = node.toString() and
tag = "path-injection-barrier" and
value = ""
)
or
exists(DataFlow::Node node |
DataflowImpl::optionalBarrier(node, "normalize-path") and
location = node.getLocation() and
location.getFile().getBaseName() != "" and
element = node.toString() and
tag = "path-injection-normalize" and
value = ""
)
or
exists(DataFlow::Node node |
node instanceof Path::SafeAccessCheck and // tends to label the node *after* the check
location = node.getLocation() and
location.getFile().getBaseName() != "" and
element = node.toString() and
tag = "path-injection-checked" and
value = ""
)
}
}

View File

@@ -13,10 +13,10 @@ fn tainted_path_handler_bad(
//#[handler]
fn tainted_path_handler_good(Query(file_name): Query<String>) -> Result<String> {
// GOOD: ensure that the filename has no path separators or parent directory references
if file_name.contains("..") || file_name.contains("/") || file_name.contains("\\") {
if file_name.contains("..") || file_name.contains("/") || file_name.contains("\\") { // $ path-injection-barrier
return Err(Error::from_status(StatusCode::BAD_REQUEST));
}
let file_path = PathBuf::from(file_name);
let file_path = PathBuf::from(file_name); // $ path-injection-barrier (following the last `.contains` check)
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink
}
@@ -29,7 +29,7 @@ fn tainted_path_handler_folder_good(Query(file_path): Query<String>) -> Result<S
if !file_path.starts_with(public_path) {
return Err(Error::from_status(StatusCode::BAD_REQUEST));
}
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-checked path-injection-sink
}
//#[handler]
@@ -42,7 +42,7 @@ fn tainted_path_handler_folder_almost_good1(
if !file_path.starts_with(public_path) {
return Err(Error::from_status(StatusCode::BAD_REQUEST));
}
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink MISSING: Alert[rust/path-injection]=remote2 -- we cannot resolve the `join` call above, because it needs a `PathBuf -> Path` `Deref`
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-checked path-injection-sink MISSING: Alert[rust/path-injection]=remote2 -- we cannot resolve the `join` call above, because it needs a `PathBuf -> Path` `Deref`
}
//#[handler]
@@ -54,7 +54,7 @@ fn tainted_path_handler_folder_good_simpler(Query(file_path): Query<String>) ->
if !file_path.starts_with(public_path) {
return Err(Error::from_status(StatusCode::BAD_REQUEST));
}
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-checked path-injection-sink
}
//#[handler]
@@ -67,7 +67,7 @@ fn tainted_path_handler_folder_almost_good1_simpler(
if !file_path.starts_with(public_path) {
return Err(Error::from_status(StatusCode::BAD_REQUEST));
}
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink MISSING: Alert[rust/path-injection]=remote3
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-checked path-injection-sink MISSING: Alert[rust/path-injection]=remote3
}
//#[handler]
@@ -81,7 +81,7 @@ fn tainted_path_handler_folder_almost_good2(
if file_path.starts_with(public_path) {
return Err(Error::from_status(StatusCode::BAD_REQUEST));
}
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink MISSING: Alert[rust/path-injection]=remote4 -- we cannot resolve the `join` call above, because it needs a `PathBuf -> Path` `Deref`
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink MISSING: path-injection-checked Alert[rust/path-injection]=remote4 -- we cannot resolve the `join` call above, because it needs a `PathBuf -> Path` `Deref`
}
//#[handler]
@@ -94,7 +94,7 @@ fn tainted_path_handler_folder_almost_good3(
if !file_path.starts_with(public_path) {
return Err(Error::from_status(StatusCode::BAD_REQUEST));
}
let file_path = file_path.canonicalize().unwrap();
let file_path = file_path.canonicalize().unwrap(); // $ path-injection-checked
fs::read_to_string(file_path).map_err(InternalServerError) // $ path-injection-sink MISSING: Alert[rust/path-injection]=remote5
}