mirror of
https://github.com/github/codeql.git
synced 2026-04-26 17:25:19 +02:00
Rust: Add new MaD format based on QL-computed canonical paths
This commit is contained in:
@@ -31,6 +31,11 @@ module Input implements InputSig<Location, RustDataFlow> {
|
||||
crate = ""
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if the associated call resolves to `path`. */
|
||||
final predicate callResolvesTo(string path) {
|
||||
path = this.getCall().getStaticTarget().(Addressable).getCanonicalPath()
|
||||
}
|
||||
}
|
||||
|
||||
abstract class SourceBase extends SourceSinkBase { }
|
||||
|
||||
@@ -4,21 +4,19 @@
|
||||
* The extensible relations have the following columns:
|
||||
*
|
||||
* - Sources:
|
||||
* `crate; path; output; kind; provenance`
|
||||
* `path; output; kind; provenance`
|
||||
* - Sinks:
|
||||
* `crate; path; input; kind; provenance`
|
||||
* `path; input; kind; provenance`
|
||||
* - Summaries:
|
||||
* `crate; path; input; output; kind; provenance`
|
||||
* `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
|
||||
* 1. The `path` column selects a function with the given canonical path.
|
||||
* 2. The `input` column specifies how data enters the element selected by the
|
||||
* first column, and the `output` column specifies how data leaves the
|
||||
* element selected by the first column. Both `input` and `output` are
|
||||
* `.`-separated lists of "access path tokens" to resolve, starting at the
|
||||
* selected function.
|
||||
*
|
||||
@@ -34,12 +32,12 @@
|
||||
* - `Field[t(i)]`: position `i` inside the variant/struct with canonical path `v`, for example
|
||||
* `Field[core::option::Option::Some(0)]`.
|
||||
* - `Field[i]`: the `i`th element of a tuple.
|
||||
* 4. The `kind` column is a tag that can be referenced from QL to determine to
|
||||
* 3. 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
|
||||
* 4. The `provenance` column is mainly used internally, and should be set to `"manual"` for
|
||||
* all custom models.
|
||||
*/
|
||||
|
||||
@@ -66,6 +64,19 @@ extensible predicate sourceModelDeprecated(
|
||||
QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if in a call to the function with canonical path `path`, 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 path, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* DEPRECATED: Do not use.
|
||||
*
|
||||
@@ -84,6 +95,20 @@ extensible predicate sinkModelDeprecated(
|
||||
QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if in a call to the function with canonical path `path`, 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 path, string input, string kind, string provenance, QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* DEPRECATED: Do not use.
|
||||
*
|
||||
@@ -99,6 +124,18 @@ extensible predicate summaryModelDeprecated(
|
||||
QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if in a call to the function with canonical path `path`, 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 path, string input, string output, string kind, string provenance,
|
||||
QlBuiltins::ExtensionId madId
|
||||
);
|
||||
|
||||
/**
|
||||
* Holds if the given extension tuple `madId` should pretty-print as `model`.
|
||||
*
|
||||
@@ -110,15 +147,30 @@ predicate interpretModelForTest(QlBuiltins::ExtensionId madId, string model) {
|
||||
model = "Source: " + crate + "; " + path + "; " + output + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string path, string output, string kind |
|
||||
sourceModel(path, kind, output, _, madId) and
|
||||
model = "Source: " + path + "; " + output + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string crate, string path, string input, string kind |
|
||||
sinkModelDeprecated(crate, path, kind, input, _, madId) and
|
||||
model = "Sink: " + crate + "; " + path + "; " + input + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string path, string input, string kind |
|
||||
sinkModel(path, kind, input, _, madId) and
|
||||
model = "Sink: " + path + "; " + input + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string type, string path, string input, string output, string kind |
|
||||
summaryModelDeprecated(type, path, input, output, kind, _, madId) and
|
||||
model = "Summary: " + type + "; " + path + "; " + input + "; " + output + "; " + kind
|
||||
)
|
||||
or
|
||||
exists(string path, string input, string output, string kind |
|
||||
summaryModel(path, input, output, kind, _, madId) and
|
||||
model = "Summary: " + path + "; " + input + "; " + output + "; " + kind
|
||||
)
|
||||
}
|
||||
|
||||
private class SummarizedCallableFromModelDeprecated extends SummarizedCallable::Range {
|
||||
@@ -151,6 +203,30 @@ private class SummarizedCallableFromModelDeprecated extends SummarizedCallable::
|
||||
}
|
||||
}
|
||||
|
||||
private class SummarizedCallableFromModel extends SummarizedCallable::Range {
|
||||
private string path;
|
||||
|
||||
SummarizedCallableFromModel() {
|
||||
summaryModel(path, _, _, _, _, _) and
|
||||
this.getCanonicalPath() = path
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
) {
|
||||
exists(string kind, QlBuiltins::ExtensionId madId |
|
||||
summaryModel(path, input, output, kind, _, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
|
|
||||
kind = "value" and
|
||||
preservesValue = true
|
||||
or
|
||||
kind = "taint" and
|
||||
preservesValue = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class FlowSourceFromModelDeprecated extends FlowSource::Range {
|
||||
private string crate;
|
||||
private string path;
|
||||
@@ -168,6 +244,22 @@ private class FlowSourceFromModelDeprecated extends FlowSource::Range {
|
||||
}
|
||||
}
|
||||
|
||||
private class FlowSourceFromModel extends FlowSource::Range {
|
||||
private string path;
|
||||
|
||||
FlowSourceFromModel() {
|
||||
sourceModel(path, _, _, _, _) and
|
||||
this.callResolvesTo(path)
|
||||
}
|
||||
|
||||
override predicate isSource(string output, string kind, Provenance provenance, string model) {
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
sourceModel(path, output, kind, provenance, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class FlowSinkFromModelDeprecated extends FlowSink::Range {
|
||||
private string crate;
|
||||
private string path;
|
||||
@@ -184,3 +276,19 @@ private class FlowSinkFromModelDeprecated extends FlowSink::Range {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class FlowSinkFromModel extends FlowSink::Range {
|
||||
private string path;
|
||||
|
||||
FlowSinkFromModel() {
|
||||
sinkModel(path, _, _, _, _) and
|
||||
this.callResolvesTo(path)
|
||||
}
|
||||
|
||||
override predicate isSink(string input, string kind, Provenance provenance, string model) {
|
||||
exists(QlBuiltins::ExtensionId madId |
|
||||
sinkModel(path, input, kind, provenance, madId) and
|
||||
model = "MaD:" + madId.toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,25 @@ extensions:
|
||||
pack: codeql/rust-all
|
||||
extensible: sourceModelDeprecated
|
||||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sourceModel
|
||||
data: []
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModelDeprecated
|
||||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModel
|
||||
data: []
|
||||
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: summaryModelDeprecated
|
||||
data: []
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: summaryModel
|
||||
data: []
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
models
|
||||
| 1 | Sink: repo::test; <crate::MyFieldEnum>::sink; test-sink; Argument[self].Field[main::MyFieldEnum::D::field_d] |
|
||||
| 2 | Sink: repo::test; crate::enum_sink; test-sink; Argument[0].Field[main::MyFieldEnum::C::field_c] |
|
||||
| 3 | Sink: repo::test; crate::simple_sink; test-sink; Argument[0] |
|
||||
| 4 | Source: repo::test; <crate::MyFieldEnum>::source; test-source; ReturnValue.Field[main::MyFieldEnum::C::field_c] |
|
||||
| 5 | Source: repo::test; crate::arg_source; test-source; Argument[0] |
|
||||
| 6 | Source: repo::test; crate::enum_source; test-source; ReturnValue.Field[main::MyFieldEnum::D::field_d] |
|
||||
| 7 | Source: repo::test; crate::simple_source; test-source; ReturnValue |
|
||||
| 8 | Summary: repo::test; crate::apply; Argument[0]; Argument[1].Parameter[0]; value |
|
||||
| 9 | Summary: repo::test; crate::apply; Argument[1].ReturnValue; ReturnValue; value |
|
||||
| 10 | Summary: repo::test; crate::coerce; Argument[0]; ReturnValue; taint |
|
||||
| 11 | Summary: repo::test; crate::get_array_element; Argument[0].Element; ReturnValue; value |
|
||||
| 12 | Summary: repo::test; crate::get_async_number; Argument[0]; ReturnValue.Future; value |
|
||||
| 13 | Summary: repo::test; crate::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value |
|
||||
| 14 | Summary: repo::test; crate::get_tuple_element; Argument[0].Field[0]; ReturnValue; value |
|
||||
| 15 | Summary: repo::test; crate::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value |
|
||||
| 16 | Summary: repo::test; crate::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value |
|
||||
| 17 | Summary: repo::test; crate::set_array_element; Argument[0]; ReturnValue.Element; value |
|
||||
| 18 | Summary: repo::test; crate::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value |
|
||||
| 19 | Summary: repo::test; crate::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value |
|
||||
| 20 | Summary: repo::test; crate::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value |
|
||||
| 21 | Summary: repo::test; crate::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value |
|
||||
| 1 | Sink: <main::MyFieldEnum>::sink; test-sink; Argument[self].Field[main::MyFieldEnum::D::field_d] |
|
||||
| 2 | Sink: main::enum_sink; test-sink; Argument[0].Field[main::MyFieldEnum::C::field_c] |
|
||||
| 3 | Sink: main::simple_sink; test-sink; Argument[0] |
|
||||
| 4 | Source: <main::MyFieldEnum>::source; test-source; ReturnValue.Field[main::MyFieldEnum::C::field_c] |
|
||||
| 5 | Source: main::arg_source; test-source; Argument[0] |
|
||||
| 6 | Source: main::enum_source; test-source; ReturnValue.Field[main::MyFieldEnum::D::field_d] |
|
||||
| 7 | Source: main::simple_source; test-source; ReturnValue |
|
||||
| 8 | Summary: main::apply; Argument[0]; Argument[1].Parameter[0]; value |
|
||||
| 9 | Summary: main::apply; Argument[1].ReturnValue; ReturnValue; value |
|
||||
| 10 | Summary: main::coerce; Argument[0]; ReturnValue; taint |
|
||||
| 11 | Summary: main::get_array_element; Argument[0].Element; ReturnValue; value |
|
||||
| 12 | Summary: main::get_async_number; Argument[0]; ReturnValue.Future; value |
|
||||
| 13 | Summary: main::get_struct_field; Argument[0].Field[main::MyStruct::field1]; ReturnValue; value |
|
||||
| 14 | Summary: main::get_tuple_element; Argument[0].Field[0]; ReturnValue; value |
|
||||
| 15 | Summary: main::get_var_field; Argument[0].Field[main::MyFieldEnum::C::field_c]; ReturnValue; value |
|
||||
| 16 | Summary: main::get_var_pos; Argument[0].Field[main::MyPosEnum::A(0)]; ReturnValue; value |
|
||||
| 17 | Summary: main::set_array_element; Argument[0]; ReturnValue.Element; value |
|
||||
| 18 | Summary: main::set_struct_field; Argument[0]; ReturnValue.Field[main::MyStruct::field2]; value |
|
||||
| 19 | Summary: main::set_tuple_element; Argument[0]; ReturnValue.Field[1]; value |
|
||||
| 20 | Summary: main::set_var_field; Argument[0]; ReturnValue.Field[main::MyFieldEnum::D::field_d]; value |
|
||||
| 21 | Summary: main::set_var_pos; Argument[0]; ReturnValue.Field[main::MyPosEnum::B(0)]; value |
|
||||
edges
|
||||
| main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | |
|
||||
| main.rs:15:9:15:9 | s | main.rs:16:19:16:19 | s | provenance | |
|
||||
|
||||
@@ -3,32 +3,32 @@ extensions:
|
||||
pack: codeql/rust-all
|
||||
extensible: sourceModel
|
||||
data:
|
||||
- ["repo::test", "crate::simple_source", "ReturnValue", "test-source", "manual"]
|
||||
- ["repo::test", "crate::enum_source", "ReturnValue.Field[main::MyFieldEnum::D::field_d]", "test-source", "manual"]
|
||||
- ["repo::test", "<crate::MyFieldEnum>::source", "ReturnValue.Field[main::MyFieldEnum::C::field_c]", "test-source", "manual"]
|
||||
- ["repo::test", "crate::arg_source", "Argument[0]", "test-source", "manual"]
|
||||
- ["main::simple_source", "ReturnValue", "test-source", "manual"]
|
||||
- ["main::enum_source", "ReturnValue.Field[main::MyFieldEnum::D::field_d]", "test-source", "manual"]
|
||||
- ["<main::MyFieldEnum>::source", "ReturnValue.Field[main::MyFieldEnum::C::field_c]", "test-source", "manual"]
|
||||
- ["main::arg_source", "Argument[0]", "test-source", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: sinkModelDeprecated
|
||||
extensible: sinkModel
|
||||
data:
|
||||
- ["repo::test", "crate::simple_sink", "Argument[0]", "test-sink", "manual"]
|
||||
- ["repo::test", "crate::enum_sink", "Argument[0].Field[main::MyFieldEnum::C::field_c]", "test-sink", "manual"]
|
||||
- ["repo::test", "<crate::MyFieldEnum>::sink", "Argument[self].Field[main::MyFieldEnum::D::field_d]", "test-sink", "manual"]
|
||||
- ["main::simple_sink", "Argument[0]", "test-sink", "manual"]
|
||||
- ["main::enum_sink", "Argument[0].Field[main::MyFieldEnum::C::field_c]", "test-sink", "manual"]
|
||||
- ["<main::MyFieldEnum>::sink", "Argument[self].Field[main::MyFieldEnum::D::field_d]", "test-sink", "manual"]
|
||||
- addsTo:
|
||||
pack: codeql/rust-all
|
||||
extensible: summaryModelDeprecated
|
||||
extensible: summaryModel
|
||||
data:
|
||||
- ["repo::test", "crate::coerce", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["repo::test", "crate::get_var_pos", "Argument[0].Field[main::MyPosEnum::A(0)]", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_var_pos", "Argument[0]", "ReturnValue.Field[main::MyPosEnum::B(0)]", "value", "manual"]
|
||||
- ["repo::test", "crate::get_var_field", "Argument[0].Field[main::MyFieldEnum::C::field_c]", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_var_field", "Argument[0]", "ReturnValue.Field[main::MyFieldEnum::D::field_d]", "value", "manual"]
|
||||
- ["repo::test", "crate::get_struct_field", "Argument[0].Field[main::MyStruct::field1]", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_struct_field", "Argument[0]", "ReturnValue.Field[main::MyStruct::field2]", "value", "manual"]
|
||||
- ["repo::test", "crate::get_array_element", "Argument[0].Element", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_array_element", "Argument[0]", "ReturnValue.Element", "value", "manual"]
|
||||
- ["repo::test", "crate::get_tuple_element", "Argument[0].Field[0]", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::set_tuple_element", "Argument[0]", "ReturnValue.Field[1]", "value", "manual"]
|
||||
- ["repo::test", "crate::apply", "Argument[0]", "Argument[1].Parameter[0]", "value", "manual"]
|
||||
- ["repo::test", "crate::apply", "Argument[1].ReturnValue", "ReturnValue", "value", "manual"]
|
||||
- ["repo::test", "crate::get_async_number", "Argument[0]", "ReturnValue.Future", "value", "manual"]
|
||||
- ["main::coerce", "Argument[0]", "ReturnValue", "taint", "manual"]
|
||||
- ["main::get_var_pos", "Argument[0].Field[main::MyPosEnum::A(0)]", "ReturnValue", "value", "manual"]
|
||||
- ["main::set_var_pos", "Argument[0]", "ReturnValue.Field[main::MyPosEnum::B(0)]", "value", "manual"]
|
||||
- ["main::get_var_field", "Argument[0].Field[main::MyFieldEnum::C::field_c]", "ReturnValue", "value", "manual"]
|
||||
- ["main::set_var_field", "Argument[0]", "ReturnValue.Field[main::MyFieldEnum::D::field_d]", "value", "manual"]
|
||||
- ["main::get_struct_field", "Argument[0].Field[main::MyStruct::field1]", "ReturnValue", "value", "manual"]
|
||||
- ["main::set_struct_field", "Argument[0]", "ReturnValue.Field[main::MyStruct::field2]", "value", "manual"]
|
||||
- ["main::get_array_element", "Argument[0].Element", "ReturnValue", "value", "manual"]
|
||||
- ["main::set_array_element", "Argument[0]", "ReturnValue.Element", "value", "manual"]
|
||||
- ["main::get_tuple_element", "Argument[0].Field[0]", "ReturnValue", "value", "manual"]
|
||||
- ["main::set_tuple_element", "Argument[0]", "ReturnValue.Field[1]", "value", "manual"]
|
||||
- ["main::apply", "Argument[0]", "Argument[1].Parameter[0]", "value", "manual"]
|
||||
- ["main::apply", "Argument[1].ReturnValue", "ReturnValue", "value", "manual"]
|
||||
- ["main::get_async_number", "Argument[0]", "ReturnValue.Future", "value", "manual"]
|
||||
|
||||
Reference in New Issue
Block a user