mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #18231 from hvitved/rust/models-as-data-summaries
Rust: Models-as-data for flow summaries
This commit is contained in:
@@ -7,17 +7,7 @@ private import codeql.rust.elements.internal.CallExprBaseImpl::Impl as CallExprB
|
||||
// import all instances below
|
||||
private module Summaries {
|
||||
private import codeql.rust.Frameworks
|
||||
|
||||
// TODO: Use models-as-data when it's available
|
||||
private class UnwrapSummary extends SummarizedCallable::Range {
|
||||
UnwrapSummary() { this = "lang:core::_::<crate::option::Option>::unwrap" }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[self].Variant[crate::option::Option::Some(0)]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
private import codeql.rust.dataflow.internal.ModelsAsData
|
||||
}
|
||||
|
||||
/** Provides the `Range` class used to define the extent of `LibraryCallable`. */
|
||||
@@ -62,7 +52,7 @@ module SummarizedCallable {
|
||||
*
|
||||
* `preservesValue` indicates whether this is a value-preserving step or a taint-step.
|
||||
*/
|
||||
abstract predicate propagatesFlow(string input, string output, boolean preservesValue);
|
||||
predicate propagatesFlow(string input, string output, boolean preservesValue) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -597,7 +597,7 @@ private class VariantFieldContent extends VariantContent, TVariantFieldContent {
|
||||
}
|
||||
|
||||
/** A canonical path pointing to a struct. */
|
||||
private class StructCanonicalPath extends MkStructCanonicalPath {
|
||||
class StructCanonicalPath extends MkStructCanonicalPath {
|
||||
CrateOriginOption crate;
|
||||
string path;
|
||||
|
||||
@@ -606,6 +606,8 @@ private class StructCanonicalPath extends MkStructCanonicalPath {
|
||||
/** Gets the underlying struct. */
|
||||
Struct getStruct() { hasExtendedCanonicalPath(result, crate, path) }
|
||||
|
||||
string getExtendedCanonicalPath() { result = path }
|
||||
|
||||
string toString() { result = this.getStruct().getName().getText() }
|
||||
|
||||
Location getLocation() { result = this.getStruct().getLocation() }
|
||||
|
||||
@@ -32,6 +32,22 @@ module Input implements InputSig<Location, RustDataFlow> {
|
||||
arg = v.getExtendedCanonicalPath() + "::" + field
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(StructCanonicalPath s, string field |
|
||||
result = "Struct" and
|
||||
c = TStructFieldContent(s, field) and
|
||||
arg = s.getExtendedCanonicalPath() + "::" + field
|
||||
)
|
||||
or
|
||||
result = "ArrayElement" and
|
||||
c = TArrayElement() and
|
||||
arg = ""
|
||||
or
|
||||
exists(int pos |
|
||||
result = "Tuple" and
|
||||
c = TTuplePositionContent(pos) and
|
||||
arg = pos.toString()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
140
rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll
Normal file
140
rust/ql/lib/codeql/rust/dataflow/internal/ModelsAsData.qll
Normal file
@@ -0,0 +1,140 @@
|
||||
/**
|
||||
* Defines extensible predicates for contributing library models from data extensions.
|
||||
*
|
||||
* The extensible relations have the following columns:
|
||||
*
|
||||
* - Sources:
|
||||
* `crate; path; output; kind; provenance`
|
||||
* - Sinks:
|
||||
* `crate; path; input; kind; provenance`
|
||||
* - Summaries:
|
||||
* `crate; path; input; output; kind; provenance`
|
||||
*
|
||||
* The interpretation of a row is similar to API-graphs with a left-to-right
|
||||
* reading.
|
||||
*
|
||||
* 1. The `crate` column selects a crate.
|
||||
* 2. The `path` column selects a function with the given canonical path within
|
||||
* the crate.
|
||||
* 3. The `input` column specifies how data enters the element selected by the
|
||||
* first 2 columns, and the `output` column specifies how data leaves the
|
||||
* element selected by the first 2 columns. Both `input` and `output` are
|
||||
* `.`-separated lists of "access path tokens" to resolve, starting at the
|
||||
* selected function.
|
||||
*
|
||||
* The following tokens are supported:
|
||||
* - `Argument[n]`: the `n`-th argument to a call. May be a range of form `x..y` (inclusive)
|
||||
* and/or a comma-separated list.
|
||||
* - `Parameter[n]`: the `n`-th parameter of a callback. May be a range of form `x..y` (inclusive)
|
||||
* and/or a comma-separated list.
|
||||
* - `ReturnValue`: the value returned by a function call.
|
||||
* - `ArrayElement`: an element of an array.
|
||||
* - `Variant[v::f]`: field `f` of the variant with canonical path `v`, for example
|
||||
* `Variant[crate::ihex::Record::Data::value]`.
|
||||
* - `Variant[v(i)]`: position `i` inside the variant with canonical path `v`, for example
|
||||
* `Variant[crate::option::Option::Some(0)]`.
|
||||
* - `Struct[s::f]`: field `f` of the struct with canonical path `v`, for example
|
||||
* `Struct[crate::process::Child::stdin]`.
|
||||
* - `Tuple[i]`: the `i`th element of a tuple.
|
||||
* 4. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* which classes the interpreted elements should be added. For example, for
|
||||
* sources `"remote"` indicates a default remote flow source, and for summaries
|
||||
* `"taint"` indicates a default additional taint step and `"value"` indicates a
|
||||
* globally applicable value-preserving step.
|
||||
* 5. The `provenance` column is mainly used internally, and should be set to `"manual"` for
|
||||
* all custom models.
|
||||
*/
|
||||
|
||||
private import rust
|
||||
private import codeql.rust.dataflow.FlowSummary
|
||||
|
||||
/**
|
||||
* Holds if in a call to the function with canonical path `path`, defined in the
|
||||
* crate `crate`, the value referred to by `output` is a flow source of the given
|
||||
* `kind`.
|
||||
*
|
||||
* `output = "ReturnValue"` simply means the result of the call itself.
|
||||
*
|
||||
* For more information on the `kind` parameter, see
|
||||
* https://github.com/github/codeql/blob/main/docs/codeql/reusables/threat-model-description.rst.
|
||||
*/
|
||||
extensible predicate sourceModel(
|
||||
string crate, string path, string output, string kind, string provenance,
|
||||
QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if in a call to the function with canonical path `path`, defined in the
|
||||
* crate `crate`, the value referred to by `input` is a flow sink of the given
|
||||
* `kind`.
|
||||
*
|
||||
* For example, `input = Argument[0]` means the first argument of the call.
|
||||
*
|
||||
* The following kinds are supported:
|
||||
*
|
||||
* - `sql-injection`: a flow sink for SQL injection.
|
||||
*/
|
||||
extensible predicate sinkModel(
|
||||
string crate, string path, string input, string kind, string provenance,
|
||||
QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if in a call to the function with canonical path `path`, defined in the
|
||||
* crate `crate`, the value referred to by `input` can flow to the value referred
|
||||
* to by `output`.
|
||||
*
|
||||
* `kind` should be either `value` or `taint`, for value-preserving or taint-preserving
|
||||
* steps, respectively.
|
||||
*/
|
||||
extensible predicate summaryModel(
|
||||
string crate, string path, string input, string output, string kind, string provenance,
|
||||
QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
* This predicate should only be used in tests.
|
||||
*/
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
exists(string crate, string path, string output, string kind |
|
||||
sourceModel(crate, path, kind, output, _, madId) and
|
||||
model = "Source: " + crate + "; " + path + "; " + output + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string crate, string path, string input, string kind |
|
||||
sinkModel(crate, path, kind, input, _, madId) and
|
||||
model = "Sink: " + crate + "; " + path + "; " + input + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string type, string path, string input, string output, string kind |
|
||||
summaryModel(type, path, input, output, kind, _, madId) and
|
||||
model = "Summary: " + type + "; " + path + "; " + input + "; " + output + "; " + kind
|
||||
)
|
||||
}
|
||||
|
||||
private class SummarizedCallableFromModel extends SummarizedCallable::Range {
|
||||
private string crate;
|
||||
private string path;
|
||||
|
||||
SummarizedCallableFromModel() {
|
||||
summaryModel(crate, path, _, _, _, _, _) and
|
||||
this = crate + "::_::" + path
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
) {
|
||||
exists(string kind, QlBuiltins::ExtensionId madId |
|
||||
summaryModel(crate, path, input, output, kind, _, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
|
|
||||
kind = "value" and
|
||||
preservesValue = true
|
||||
or
|
||||
kind = "taint" and
|
||||
preservesValue = false
|
||||
)
|
||||
}
|
||||
}
|
||||
17
rust/ql/lib/codeql/rust/dataflow/internal/empty.model.yml
Normal file
17
rust/ql/lib/codeql/rust/dataflow/internal/empty.model.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
extensions:
|
||||
# Make sure that the extensible model predicates have at least one definition
|
||||
# to avoid errors about undefined extensionals.
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sourceModel
|
||||
data: []
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModel
|
||||
data: []
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: summaryModel
|
||||
data: []
|
||||
@@ -0,0 +1,6 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["lang:core", "<crate::option::Option>::unwrap", "Argument[self].Variant[crate::option::Option::Some(0)]", "ReturnValue", "value", "manual"]
|
||||
@@ -13,4 +13,6 @@ dependencies:
|
||||
codeql/ssa: ${workspace}
|
||||
codeql/tutorial: ${workspace}
|
||||
codeql/util: ${workspace}
|
||||
dataExtensions:
|
||||
- /**/*.model.yml
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
models
|
||||
| 1 | Summary: lang:core; <crate::option::Option>::unwrap; Argument[self].Variant[crate::option::Option::Some(0)]; ReturnValue; value |
|
||||
edges
|
||||
| main.rs:19:13:19:21 | source(...) | main.rs:20:10:20:10 | s | provenance | |
|
||||
| main.rs:24:13:24:21 | source(...) | main.rs:27:10:27:10 | c | provenance | |
|
||||
@@ -35,7 +36,7 @@ edges
|
||||
| main.rs:214:14:214:14 | n | main.rs:214:25:214:25 | n | provenance | |
|
||||
| main.rs:224:14:224:29 | Some(...) [Some] | main.rs:225:10:225:11 | s1 [Some] | provenance | |
|
||||
| main.rs:224:19:224:28 | source(...) | main.rs:224:14:224:29 | Some(...) [Some] | provenance | |
|
||||
| main.rs:225:10:225:11 | s1 [Some] | main.rs:225:10:225:20 | s1.unwrap(...) | provenance | |
|
||||
| main.rs:225:10:225:11 | s1 [Some] | main.rs:225:10:225:20 | s1.unwrap(...) | provenance | MaD:1 |
|
||||
| main.rs:229:14:229:29 | Some(...) [Some] | main.rs:231:14:231:15 | s1 [Some] | provenance | |
|
||||
| main.rs:229:19:229:28 | source(...) | main.rs:229:14:229:29 | Some(...) [Some] | provenance | |
|
||||
| main.rs:231:14:231:15 | s1 [Some] | main.rs:231:14:231:16 | TryExpr | provenance | |
|
||||
|
||||
@@ -90,11 +90,102 @@ fn test_set_var_field() {
|
||||
}
|
||||
}
|
||||
|
||||
struct MyStruct {
|
||||
field1: i64,
|
||||
field2: i64,
|
||||
}
|
||||
|
||||
// has a flow model
|
||||
fn get_struct_field(s: MyStruct) -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
fn test_get_struct_field() {
|
||||
let s = source(6);
|
||||
let my_struct = MyStruct {
|
||||
field1: s,
|
||||
field2: 0,
|
||||
};
|
||||
sink(get_struct_field(my_struct)); // $ hasValueFlow=6
|
||||
let my_struct2 = MyStruct {
|
||||
field1: 0,
|
||||
field2: s,
|
||||
};
|
||||
sink(get_struct_field(my_struct2));
|
||||
}
|
||||
|
||||
// has a flow model
|
||||
fn set_struct_field(i: i64) -> MyStruct {
|
||||
MyStruct {
|
||||
field1: 0,
|
||||
field2: 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn test_set_struct_field() {
|
||||
let s = source(7);
|
||||
let my_struct = set_struct_field(s);
|
||||
sink(my_struct.field1);
|
||||
sink(my_struct.field2); // $ MISSING: hasValueFlow=7
|
||||
}
|
||||
|
||||
// has a flow model
|
||||
fn get_array_element(a: [i64; 1]) -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
fn test_get_array_element() {
|
||||
let s = source(8);
|
||||
sink(get_array_element([s])); // $ hasValueFlow=8
|
||||
}
|
||||
|
||||
// has a flow model
|
||||
fn set_array_element(i: i64) -> [i64; 1] {
|
||||
[0]
|
||||
}
|
||||
|
||||
fn test_set_array_element() {
|
||||
let s = source(9);
|
||||
let arr = set_array_element(s);
|
||||
sink(arr[0]); // $ hasValueFlow=9
|
||||
}
|
||||
|
||||
// has a flow model
|
||||
fn get_tuple_element(a: (i64, i64)) -> i64 {
|
||||
0
|
||||
}
|
||||
|
||||
fn test_get_tuple_element() {
|
||||
let s = source(10);
|
||||
let t = (s, 0);
|
||||
sink(get_tuple_element(t)); // $ hasValueFlow=10
|
||||
let t = (0, s);
|
||||
sink(get_tuple_element(t));
|
||||
}
|
||||
|
||||
// has a flow model
|
||||
fn set_tuple_element(i: i64) -> (i64, i64) {
|
||||
(0, 1)
|
||||
}
|
||||
|
||||
fn test_set_tuple_element() {
|
||||
let s = source(11);
|
||||
let t = set_tuple_element(s);
|
||||
sink(t.0);
|
||||
sink(t.1); // $ hasValueFlow=11
|
||||
}
|
||||
|
||||
fn main() {
|
||||
test_identify();
|
||||
test_get_var_pos();
|
||||
test_set_var_pos();
|
||||
test_get_var_field();
|
||||
test_set_var_field();
|
||||
test_get_struct_field();
|
||||
test_set_struct_field();
|
||||
test_get_array_element();
|
||||
test_set_array_element();
|
||||
test_get_tuple_element();
|
||||
test_set_tuple_element();
|
||||
let dummy = Some(0); // ensure that the the `lang:core` crate is extracted
|
||||
}
|
||||
|
||||
@@ -1,25 +1,35 @@
|
||||
models
|
||||
| 1 | Summary: repo::test; crate::coerce; Argument[0]; ReturnValue; taint |
|
||||
| 2 | Summary: repo::test; crate::get_array_element; Argument[0].ArrayElement; ReturnValue; value |
|
||||
| 3 | Summary: repo::test; crate::get_struct_field; Argument[0].Struct[crate::MyStruct::field1]; ReturnValue; value |
|
||||
| 4 | Summary: repo::test; crate::get_tuple_element; Argument[0].Tuple[0]; ReturnValue; value |
|
||||
| 5 | Summary: repo::test; crate::get_var_field; Argument[0].Variant[crate::MyFieldEnum::C::field_c]; ReturnValue; value |
|
||||
| 6 | Summary: repo::test; crate::get_var_pos; Argument[0].Variant[crate::MyPosEnum::A(0)]; ReturnValue; value |
|
||||
| 7 | Summary: repo::test; crate::set_array_element; Argument[0]; ReturnValue.ArrayElement; value |
|
||||
| 8 | Summary: repo::test; crate::set_tuple_element; Argument[0]; ReturnValue.Tuple[1]; value |
|
||||
| 9 | Summary: repo::test; crate::set_var_field; Argument[0]; ReturnValue.Variant[crate::MyFieldEnum::D::field_d]; value |
|
||||
| 10 | Summary: repo::test; crate::set_var_pos; Argument[0]; ReturnValue.Variant[crate::MyPosEnum::B(0)]; value |
|
||||
edges
|
||||
| main.rs:15:13:15:21 | source(...) | main.rs:16:19:16:19 | s | provenance | |
|
||||
| main.rs:15:13:15:21 | source(...) | main.rs:16:19:16:19 | s | provenance | |
|
||||
| main.rs:16:19:16:19 | s | main.rs:16:10:16:20 | identity(...) | provenance | |
|
||||
| main.rs:16:19:16:19 | s | main.rs:16:10:16:20 | identity(...) | provenance | |
|
||||
| main.rs:16:19:16:19 | s | main.rs:16:10:16:20 | identity(...) | provenance | QL |
|
||||
| main.rs:16:19:16:19 | s | main.rs:16:10:16:20 | identity(...) | provenance | QL |
|
||||
| main.rs:25:13:25:22 | source(...) | main.rs:26:17:26:17 | s | provenance | |
|
||||
| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | |
|
||||
| main.rs:26:17:26:17 | s | main.rs:26:10:26:18 | coerce(...) | provenance | MaD:1 |
|
||||
| main.rs:40:13:40:21 | source(...) | main.rs:41:27:41:27 | s | provenance | |
|
||||
| main.rs:40:13:40:21 | source(...) | main.rs:41:27:41:27 | s | provenance | |
|
||||
| main.rs:41:14:41:28 | ...::A(...) [A] | main.rs:42:22:42:23 | e1 [A] | provenance | |
|
||||
| main.rs:41:14:41:28 | ...::A(...) [A] | main.rs:42:22:42:23 | e1 [A] | provenance | |
|
||||
| main.rs:41:27:41:27 | s | main.rs:41:14:41:28 | ...::A(...) [A] | provenance | |
|
||||
| main.rs:41:27:41:27 | s | main.rs:41:14:41:28 | ...::A(...) [A] | provenance | |
|
||||
| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | |
|
||||
| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | |
|
||||
| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:6 |
|
||||
| main.rs:42:22:42:23 | e1 [A] | main.rs:42:10:42:24 | get_var_pos(...) | provenance | MaD:6 |
|
||||
| main.rs:53:13:53:21 | source(...) | main.rs:54:26:54:26 | s | provenance | |
|
||||
| main.rs:53:13:53:21 | source(...) | main.rs:54:26:54:26 | s | provenance | |
|
||||
| main.rs:54:14:54:27 | set_var_pos(...) [B] | main.rs:57:9:57:23 | ...::B(...) [B] | provenance | |
|
||||
| main.rs:54:14:54:27 | set_var_pos(...) [B] | main.rs:57:9:57:23 | ...::B(...) [B] | provenance | |
|
||||
| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | |
|
||||
| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | |
|
||||
| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:10 |
|
||||
| main.rs:54:26:54:26 | s | main.rs:54:14:54:27 | set_var_pos(...) [B] | provenance | MaD:10 |
|
||||
| main.rs:57:9:57:23 | ...::B(...) [B] | main.rs:57:22:57:22 | i | provenance | |
|
||||
| main.rs:57:9:57:23 | ...::B(...) [B] | main.rs:57:22:57:22 | i | provenance | |
|
||||
| main.rs:57:22:57:22 | i | main.rs:57:33:57:33 | i | provenance | |
|
||||
@@ -30,18 +40,56 @@ edges
|
||||
| main.rs:73:14:73:42 | ...::C {...} [C] | main.rs:74:24:74:25 | e1 [C] | provenance | |
|
||||
| main.rs:73:40:73:40 | s | main.rs:73:14:73:42 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:73:40:73:40 | s | main.rs:73:14:73:42 | ...::C {...} [C] | provenance | |
|
||||
| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | |
|
||||
| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | |
|
||||
| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:5 |
|
||||
| main.rs:74:24:74:25 | e1 [C] | main.rs:74:10:74:26 | get_var_field(...) | provenance | MaD:5 |
|
||||
| main.rs:85:13:85:21 | source(...) | main.rs:86:28:86:28 | s | provenance | |
|
||||
| main.rs:85:13:85:21 | source(...) | main.rs:86:28:86:28 | s | provenance | |
|
||||
| main.rs:86:14:86:29 | set_var_field(...) [D] | main.rs:89:9:89:37 | ...::D {...} [D] | provenance | |
|
||||
| main.rs:86:14:86:29 | set_var_field(...) [D] | main.rs:89:9:89:37 | ...::D {...} [D] | provenance | |
|
||||
| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | |
|
||||
| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | |
|
||||
| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:9 |
|
||||
| main.rs:86:28:86:28 | s | main.rs:86:14:86:29 | set_var_field(...) [D] | provenance | MaD:9 |
|
||||
| main.rs:89:9:89:37 | ...::D {...} [D] | main.rs:89:35:89:35 | i | provenance | |
|
||||
| main.rs:89:9:89:37 | ...::D {...} [D] | main.rs:89:35:89:35 | i | provenance | |
|
||||
| main.rs:89:35:89:35 | i | main.rs:89:47:89:47 | i | provenance | |
|
||||
| main.rs:89:35:89:35 | i | main.rs:89:47:89:47 | i | provenance | |
|
||||
| main.rs:104:13:104:21 | source(...) | main.rs:106:17:106:17 | s | provenance | |
|
||||
| main.rs:104:13:104:21 | source(...) | main.rs:106:17:106:17 | s | provenance | |
|
||||
| main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | main.rs:109:27:109:35 | my_struct [MyStruct.field1] | provenance | |
|
||||
| main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | main.rs:109:27:109:35 | my_struct [MyStruct.field1] | provenance | |
|
||||
| main.rs:106:17:106:17 | s | main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | provenance | |
|
||||
| main.rs:106:17:106:17 | s | main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | provenance | |
|
||||
| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:3 |
|
||||
| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | main.rs:109:10:109:36 | get_struct_field(...) | provenance | MaD:3 |
|
||||
| main.rs:138:13:138:21 | source(...) | main.rs:139:29:139:29 | s | provenance | |
|
||||
| main.rs:138:13:138:21 | source(...) | main.rs:139:29:139:29 | s | provenance | |
|
||||
| main.rs:139:28:139:30 | [...] [array[]] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:2 |
|
||||
| main.rs:139:28:139:30 | [...] [array[]] | main.rs:139:10:139:31 | get_array_element(...) | provenance | MaD:2 |
|
||||
| main.rs:139:29:139:29 | s | main.rs:139:28:139:30 | [...] [array[]] | provenance | |
|
||||
| main.rs:139:29:139:29 | s | main.rs:139:28:139:30 | [...] [array[]] | provenance | |
|
||||
| main.rs:148:13:148:21 | source(...) | main.rs:149:33:149:33 | s | provenance | |
|
||||
| main.rs:148:13:148:21 | source(...) | main.rs:149:33:149:33 | s | provenance | |
|
||||
| main.rs:149:15:149:34 | set_array_element(...) [array[]] | main.rs:150:10:150:12 | arr [array[]] | provenance | |
|
||||
| main.rs:149:15:149:34 | set_array_element(...) [array[]] | main.rs:150:10:150:12 | arr [array[]] | provenance | |
|
||||
| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [array[]] | provenance | MaD:7 |
|
||||
| main.rs:149:33:149:33 | s | main.rs:149:15:149:34 | set_array_element(...) [array[]] | provenance | MaD:7 |
|
||||
| main.rs:150:10:150:12 | arr [array[]] | main.rs:150:10:150:15 | arr[0] | provenance | |
|
||||
| main.rs:150:10:150:12 | arr [array[]] | main.rs:150:10:150:15 | arr[0] | provenance | |
|
||||
| main.rs:159:13:159:22 | source(...) | main.rs:160:14:160:14 | s | provenance | |
|
||||
| main.rs:159:13:159:22 | source(...) | main.rs:160:14:160:14 | s | provenance | |
|
||||
| main.rs:160:13:160:18 | TupleExpr [tuple.0] | main.rs:161:28:161:28 | t [tuple.0] | provenance | |
|
||||
| main.rs:160:13:160:18 | TupleExpr [tuple.0] | main.rs:161:28:161:28 | t [tuple.0] | provenance | |
|
||||
| main.rs:160:14:160:14 | s | main.rs:160:13:160:18 | TupleExpr [tuple.0] | provenance | |
|
||||
| main.rs:160:14:160:14 | s | main.rs:160:13:160:18 | TupleExpr [tuple.0] | provenance | |
|
||||
| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:4 |
|
||||
| main.rs:161:28:161:28 | t [tuple.0] | main.rs:161:10:161:29 | get_tuple_element(...) | provenance | MaD:4 |
|
||||
| main.rs:172:13:172:22 | source(...) | main.rs:173:31:173:31 | s | provenance | |
|
||||
| main.rs:172:13:172:22 | source(...) | main.rs:173:31:173:31 | s | provenance | |
|
||||
| main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | main.rs:175:10:175:10 | t [tuple.1] | provenance | |
|
||||
| main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | main.rs:175:10:175:10 | t [tuple.1] | provenance | |
|
||||
| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:8 |
|
||||
| main.rs:173:31:173:31 | s | main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | provenance | MaD:8 |
|
||||
| main.rs:175:10:175:10 | t [tuple.1] | main.rs:175:10:175:12 | t.1 | provenance | |
|
||||
| main.rs:175:10:175:10 | t [tuple.1] | main.rs:175:10:175:12 | t.1 | provenance | |
|
||||
nodes
|
||||
| main.rs:15:13:15:21 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:15:13:15:21 | source(...) | semmle.label | source(...) |
|
||||
@@ -96,6 +144,54 @@ nodes
|
||||
| main.rs:89:35:89:35 | i | semmle.label | i |
|
||||
| main.rs:89:47:89:47 | i | semmle.label | i |
|
||||
| main.rs:89:47:89:47 | i | semmle.label | i |
|
||||
| main.rs:104:13:104:21 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:104:13:104:21 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | semmle.label | MyStruct {...} [MyStruct.field1] |
|
||||
| main.rs:105:21:108:5 | MyStruct {...} [MyStruct.field1] | semmle.label | MyStruct {...} [MyStruct.field1] |
|
||||
| main.rs:106:17:106:17 | s | semmle.label | s |
|
||||
| main.rs:106:17:106:17 | s | semmle.label | s |
|
||||
| main.rs:109:10:109:36 | get_struct_field(...) | semmle.label | get_struct_field(...) |
|
||||
| main.rs:109:10:109:36 | get_struct_field(...) | semmle.label | get_struct_field(...) |
|
||||
| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | semmle.label | my_struct [MyStruct.field1] |
|
||||
| main.rs:109:27:109:35 | my_struct [MyStruct.field1] | semmle.label | my_struct [MyStruct.field1] |
|
||||
| main.rs:138:13:138:21 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:138:13:138:21 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:139:10:139:31 | get_array_element(...) | semmle.label | get_array_element(...) |
|
||||
| main.rs:139:10:139:31 | get_array_element(...) | semmle.label | get_array_element(...) |
|
||||
| main.rs:139:28:139:30 | [...] [array[]] | semmle.label | [...] [array[]] |
|
||||
| main.rs:139:28:139:30 | [...] [array[]] | semmle.label | [...] [array[]] |
|
||||
| main.rs:139:29:139:29 | s | semmle.label | s |
|
||||
| main.rs:139:29:139:29 | s | semmle.label | s |
|
||||
| main.rs:148:13:148:21 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:148:13:148:21 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:149:15:149:34 | set_array_element(...) [array[]] | semmle.label | set_array_element(...) [array[]] |
|
||||
| main.rs:149:15:149:34 | set_array_element(...) [array[]] | semmle.label | set_array_element(...) [array[]] |
|
||||
| main.rs:149:33:149:33 | s | semmle.label | s |
|
||||
| main.rs:149:33:149:33 | s | semmle.label | s |
|
||||
| main.rs:150:10:150:12 | arr [array[]] | semmle.label | arr [array[]] |
|
||||
| main.rs:150:10:150:12 | arr [array[]] | semmle.label | arr [array[]] |
|
||||
| main.rs:150:10:150:15 | arr[0] | semmle.label | arr[0] |
|
||||
| main.rs:150:10:150:15 | arr[0] | semmle.label | arr[0] |
|
||||
| main.rs:159:13:159:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:159:13:159:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:160:13:160:18 | TupleExpr [tuple.0] | semmle.label | TupleExpr [tuple.0] |
|
||||
| main.rs:160:13:160:18 | TupleExpr [tuple.0] | semmle.label | TupleExpr [tuple.0] |
|
||||
| main.rs:160:14:160:14 | s | semmle.label | s |
|
||||
| main.rs:160:14:160:14 | s | semmle.label | s |
|
||||
| main.rs:161:10:161:29 | get_tuple_element(...) | semmle.label | get_tuple_element(...) |
|
||||
| main.rs:161:10:161:29 | get_tuple_element(...) | semmle.label | get_tuple_element(...) |
|
||||
| main.rs:161:28:161:28 | t [tuple.0] | semmle.label | t [tuple.0] |
|
||||
| main.rs:161:28:161:28 | t [tuple.0] | semmle.label | t [tuple.0] |
|
||||
| main.rs:172:13:172:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:172:13:172:22 | source(...) | semmle.label | source(...) |
|
||||
| main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | semmle.label | set_tuple_element(...) [tuple.1] |
|
||||
| main.rs:173:13:173:32 | set_tuple_element(...) [tuple.1] | semmle.label | set_tuple_element(...) [tuple.1] |
|
||||
| main.rs:173:31:173:31 | s | semmle.label | s |
|
||||
| main.rs:173:31:173:31 | s | semmle.label | s |
|
||||
| main.rs:175:10:175:10 | t [tuple.1] | semmle.label | t [tuple.1] |
|
||||
| main.rs:175:10:175:10 | t [tuple.1] | semmle.label | t [tuple.1] |
|
||||
| main.rs:175:10:175:12 | t.1 | semmle.label | t.1 |
|
||||
| main.rs:175:10:175:12 | t.1 | semmle.label | t.1 |
|
||||
subpaths
|
||||
testFailures
|
||||
invalidSpecComponent
|
||||
@@ -111,3 +207,13 @@ invalidSpecComponent
|
||||
| main.rs:74:10:74:26 | get_var_field(...) | main.rs:72:13:72:21 | source(...) | main.rs:74:10:74:26 | get_var_field(...) | $@ | main.rs:72:13:72:21 | source(...) | source(...) |
|
||||
| main.rs:89:47:89:47 | i | main.rs:85:13:85:21 | source(...) | main.rs:89:47:89:47 | i | $@ | main.rs:85:13:85:21 | source(...) | source(...) |
|
||||
| main.rs:89:47:89:47 | i | main.rs:85:13:85:21 | source(...) | main.rs:89:47:89:47 | i | $@ | main.rs:85:13:85:21 | source(...) | source(...) |
|
||||
| main.rs:109:10:109:36 | get_struct_field(...) | main.rs:104:13:104:21 | source(...) | main.rs:109:10:109:36 | get_struct_field(...) | $@ | main.rs:104:13:104:21 | source(...) | source(...) |
|
||||
| main.rs:109:10:109:36 | get_struct_field(...) | main.rs:104:13:104:21 | source(...) | main.rs:109:10:109:36 | get_struct_field(...) | $@ | main.rs:104:13:104:21 | source(...) | source(...) |
|
||||
| main.rs:139:10:139:31 | get_array_element(...) | main.rs:138:13:138:21 | source(...) | main.rs:139:10:139:31 | get_array_element(...) | $@ | main.rs:138:13:138:21 | source(...) | source(...) |
|
||||
| main.rs:139:10:139:31 | get_array_element(...) | main.rs:138:13:138:21 | source(...) | main.rs:139:10:139:31 | get_array_element(...) | $@ | main.rs:138:13:138:21 | source(...) | source(...) |
|
||||
| main.rs:150:10:150:15 | arr[0] | main.rs:148:13:148:21 | source(...) | main.rs:150:10:150:15 | arr[0] | $@ | main.rs:148:13:148:21 | source(...) | source(...) |
|
||||
| main.rs:150:10:150:15 | arr[0] | main.rs:148:13:148:21 | source(...) | main.rs:150:10:150:15 | arr[0] | $@ | main.rs:148:13:148:21 | source(...) | source(...) |
|
||||
| main.rs:161:10:161:29 | get_tuple_element(...) | main.rs:159:13:159:22 | source(...) | main.rs:161:10:161:29 | get_tuple_element(...) | $@ | main.rs:159:13:159:22 | source(...) | source(...) |
|
||||
| main.rs:161:10:161:29 | get_tuple_element(...) | main.rs:159:13:159:22 | source(...) | main.rs:161:10:161:29 | get_tuple_element(...) | $@ | main.rs:159:13:159:22 | source(...) | source(...) |
|
||||
| main.rs:175:10:175:12 | t.1 | main.rs:172:13:172:22 | source(...) | main.rs:175:10:175:12 | t.1 | $@ | main.rs:172:13:172:22 | source(...) | source(...) |
|
||||
| main.rs:175:10:175:12 | t.1 | main.rs:172:13:172:22 | source(...) | main.rs:175:10:175:12 | t.1 | $@ | main.rs:172:13:172:22 | source(...) | source(...) |
|
||||
|
||||
16
rust/ql/test/library-tests/dataflow/models/models.ext.yml
Normal file
16
rust/ql/test/library-tests/dataflow/models/models.ext.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
extensions:
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["repo::test", "crate::coerce", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["repo::test", "crate::get_var_pos", "Argument[0].Variant[crate::MyPosEnum::A(0)]", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_var_pos", "Argument[0]", "ReturnValue.Variant[crate::MyPosEnum::B(0)]", "value", "manual"]
|
||||
- ["repo::test", "crate::get_var_field", "Argument[0].Variant[crate::MyFieldEnum::C::field_c]", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_var_field", "Argument[0]", "ReturnValue.Variant[crate::MyFieldEnum::D::field_d]", "value", "manual"]
|
||||
- ["repo::test", "crate::get_struct_field", "Argument[0].Struct[crate::MyStruct::field1]", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_struct_field", "Argument[0]", "ReturnValue.Struct[crate::MyStruct::field2]", "value", "manual"]
|
||||
- ["repo::test", "crate::get_array_element", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_array_element", "Argument[0]", "ReturnValue.ArrayElement", "value", "manual"]
|
||||
- ["repo::test", "crate::get_tuple_element", "Argument[0].Tuple[0]", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_tuple_element", "Argument[0]", "ReturnValue.Tuple[1]", "value", "manual"]
|
||||
@@ -15,63 +15,18 @@ query predicate invalidSpecComponent(SummarizedCallable sc, string s, string c)
|
||||
Private::External::invalidSpecComponent(s, c)
|
||||
}
|
||||
|
||||
// not defined in `models.ext.yml`, in order to test that we can also define
|
||||
// models directly in QL
|
||||
private class SummarizedCallableIdentity extends SummarizedCallable::Range {
|
||||
SummarizedCallableIdentity() { this = "repo::test::_::crate::identity" }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string provenance
|
||||
) {
|
||||
input = "Argument[0]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableCoerce extends SummarizedCallable::Range {
|
||||
SummarizedCallableCoerce() { this = "repo::test::_::crate::coerce" }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[0]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = false
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableGetVarPos extends SummarizedCallable::Range {
|
||||
SummarizedCallableGetVarPos() { this = "repo::test::_::crate::get_var_pos" }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[0].Variant[crate::MyPosEnum::A(0)]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableSetVarPos extends SummarizedCallable::Range {
|
||||
SummarizedCallableSetVarPos() { this = "repo::test::_::crate::set_var_pos" }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[0]" and
|
||||
output = "ReturnValue.Variant[crate::MyPosEnum::B(0)]" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableGetVarField extends SummarizedCallable::Range {
|
||||
SummarizedCallableGetVarField() { this = "repo::test::_::crate::get_var_field" }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[0].Variant[crate::MyFieldEnum::C::field_c]" and
|
||||
output = "ReturnValue" and
|
||||
preservesValue = true
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableSetVarField extends SummarizedCallable::Range {
|
||||
SummarizedCallableSetVarField() { this = "repo::test::_::crate::set_var_field" }
|
||||
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
input = "Argument[0]" and
|
||||
output = "ReturnValue.Variant[crate::MyFieldEnum::D::field_d]" and
|
||||
preservesValue = true
|
||||
preservesValue = true and
|
||||
provenance = "QL"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
query: queries/security/CWE-089/SqlInjection.ql
|
||||
postprocess: utils/InlineExpectationsTestQuery.ql
|
||||
postprocess:
|
||||
- utils/PrettyPrintModels.ql
|
||||
- utils/InlineExpectationsTestQuery.ql
|
||||
|
||||
@@ -9,6 +9,7 @@ private import codeql.rust.controlflow.CfgNodes
|
||||
private import codeql.rust.dataflow.DataFlow
|
||||
private import codeql.rust.dataflow.internal.DataFlowImpl
|
||||
private import codeql.rust.dataflow.internal.TaintTrackingImpl
|
||||
private import codeql.rust.dataflow.internal.ModelsAsData as MaD
|
||||
private import internal.InlineExpectationsTestImpl as InlineExpectationsTestImpl
|
||||
|
||||
// Holds if the target expression of `call` is a path and the string representation of the path is `name`.
|
||||
@@ -38,7 +39,7 @@ private module FlowTestImpl implements InputSig<Location, RustDataFlow> {
|
||||
exists(sink)
|
||||
}
|
||||
|
||||
predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) { none() }
|
||||
predicate interpretModelForTest = MaD::interpretModelForTest/2;
|
||||
}
|
||||
|
||||
import InlineFlowTestMake<Location, RustDataFlow, RustTaintTracking, InlineExpectationsTestImpl::Impl, FlowTestImpl>
|
||||
|
||||
7
rust/ql/test/utils/PrettyPrintModels.ql
Normal file
7
rust/ql/test/utils/PrettyPrintModels.ql
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* @kind test-postprocess
|
||||
*/
|
||||
|
||||
import codeql.rust.dataflow.internal.ModelsAsData
|
||||
import codeql.dataflow.test.ProvenancePathGraph
|
||||
import codeql.dataflow.test.ProvenancePathGraph::TestPostProcessing::TranslateProvenanceResults<interpretModelForTest/2>
|
||||
8
rust/ql/test/utils/ProvenancePathGraph.qll
Normal file
8
rust/ql/test/utils/ProvenancePathGraph.qll
Normal file
@@ -0,0 +1,8 @@
|
||||
private import codeql.dataflow.DataFlow as DF
|
||||
private import codeql.dataflow.test.ProvenancePathGraph as Graph
|
||||
private import codeql.rust.dataflow.internal.ModelsAsData
|
||||
|
||||
/** Transforms a `PathGraph` by printing the provenance information. */
|
||||
module ShowProvenance<Graph::PathNodeSig PathNode, DF::PathGraphSig<PathNode> PathGraph> {
|
||||
import Graph::ShowProvenance<interpretModelForTest/2, PathNode, PathGraph>
|
||||
}
|
||||
Reference in New Issue
Block a user