Skip to content

Commit b2fe7cb

Browse files
committed
Rust: Re-factor implementation to use the new model generator interface.
1 parent 00a8cd5 commit b2fe7cb

12 files changed

+103
-78
lines changed

rust/ql/src/utils/modelgenerator/CaptureContentSummaryModels.ql

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import internal.CaptureModels
10+
import SummaryModels
1011

1112
from DataFlowSummaryTargetApi api, string flow
1213
where flow = ContentSensitive::captureFlow(api, _)

rust/ql/src/utils/modelgenerator/CaptureNeutralModels.ql

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import internal.CaptureModels
10+
import SummaryModels
1011

1112
from DataFlowSummaryTargetApi api, string noflow
1213
where noflow = Heuristic::captureNoFlow(api)

rust/ql/src/utils/modelgenerator/CaptureSinkModels.ql

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import internal.CaptureModels
10+
import SinkModels
1011

1112
from DataFlowSinkTargetApi api, string sink
1213
where sink = Heuristic::captureSink(api)

rust/ql/src/utils/modelgenerator/CaptureSourceModels.ql

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import internal.CaptureModels
10+
import SourceModels
1011

1112
from DataFlowSourceTargetApi api, string source
1213
where source = Heuristic::captureSource(api)

rust/ql/src/utils/modelgenerator/CaptureSummaryModels.ql

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import internal.CaptureModels
10+
import SummaryModels
1011

1112
from DataFlowSummaryTargetApi api, string flow
1213
where flow = captureFlow(api, _)

rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPartialPath.ql

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
private import codeql.rust.dataflow.DataFlow
1212
import utils.modelgenerator.internal.CaptureModels
13+
import SummaryModels
1314
import PartialFlow::PartialPathGraph
1415

1516
int explorationLimit() { result = 3 }

rust/ql/src/utils/modelgenerator/debug/CaptureSummaryModelsPath.ql

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
private import codeql.rust.dataflow.DataFlow
1212
import utils.modelgenerator.internal.CaptureModels
13+
import SummaryModels
1314
import Heuristic
1415
import PropagateFlow::PathGraph
1516

rust/ql/src/utils/modelgenerator/internal/CaptureModels.qll

+92-77
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ private import codeql.util.Unit
22
private import rust
33
private import rust as R
44
private import codeql.rust.dataflow.DataFlow
5-
private import codeql.rust.dataflow.internal.DataFlowImpl
5+
private import codeql.rust.dataflow.internal.DataFlowImpl as DataFlowImpl
66
private import codeql.rust.dataflow.internal.Node as Node
77
private import codeql.rust.dataflow.internal.Content
88
private import codeql.rust.dataflow.FlowSource as FlowSource
@@ -11,7 +11,25 @@ private import codeql.rust.dataflow.internal.TaintTrackingImpl
1111
private import codeql.mad.modelgenerator.internal.ModelGeneratorImpl
1212
private import codeql.rust.dataflow.internal.FlowSummaryImpl as FlowSummary
1313

14-
module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataFlow> {
14+
private predicate relevant(Function api) {
15+
// Only include functions that have a resolved path.
16+
api.hasCrateOrigin() and
17+
api.hasExtendedCanonicalPath() and
18+
(
19+
// This excludes closures (these are not exported API endpoints) and
20+
// functions without a `pub` visiblity. A function can be `pub` without
21+
// ultimately being exported by a crate, so this is an overapproximation.
22+
api.hasVisibility()
23+
or
24+
// If a method implements a public trait it is exposed through the trait.
25+
// We overapproximate this by including all trait method implementations.
26+
exists(Impl impl | impl.hasTrait() and impl.getAssocItemList().getAssocItem(_) = api)
27+
)
28+
}
29+
30+
module ModelGeneratorCommonInput implements
31+
ModelGeneratorCommonInputSig<Location, DataFlowImpl::RustDataFlow>
32+
{
1533
// NOTE: We are not using type information for now.
1634
class Type = Unit;
1735

@@ -23,55 +41,10 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
2341
Type getType() { any() }
2442
}
2543

26-
Callable getAsExprEnclosingCallable(NodeExtended node) { result = node.asExpr().getScope() }
27-
2844
Callable getEnclosingCallable(NodeExtended node) {
2945
result = node.(Node::Node).getEnclosingCallable().asCfgScope()
3046
}
3147

32-
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
33-
34-
private predicate relevant(Function api) {
35-
// Only include functions that have a resolved path.
36-
api.hasCrateOrigin() and
37-
api.hasExtendedCanonicalPath() and
38-
(
39-
// This excludes closures (these are not exported API endpoints) and
40-
// functions without a `pub` visiblity. A function can be `pub` without
41-
// ultimately being exported by a crate, so this is an overapproximation.
42-
api.hasVisibility()
43-
or
44-
// If a method implements a public trait it is exposed through the trait.
45-
// We overapproximate this by including all trait method implementations.
46-
exists(Impl impl | impl.hasTrait() and impl.getAssocItemList().getAssocItem(_) = api)
47-
)
48-
}
49-
50-
predicate isUninterestingForDataFlowModels(Callable api) { none() }
51-
52-
predicate isUninterestingForHeuristicDataFlowModels(Callable api) { none() }
53-
54-
class SourceOrSinkTargetApi extends Callable {
55-
SourceOrSinkTargetApi() { relevant(this) }
56-
}
57-
58-
class SinkTargetApi extends SourceOrSinkTargetApi { }
59-
60-
class SourceTargetApi extends SourceOrSinkTargetApi { }
61-
62-
class SummaryTargetApi extends Callable {
63-
private Callable lift;
64-
65-
SummaryTargetApi() {
66-
lift = this and
67-
relevant(this)
68-
}
69-
70-
Callable lift() { result = lift }
71-
72-
predicate isRelevant() { relevant(this) }
73-
}
74-
7548
predicate isRelevantType(Type t) { any() }
7649

7750
/**
@@ -82,7 +55,9 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
8255
string qualifierString() { result = "Argument[self]" }
8356

8457
string parameterAccess(R::ParamBase p) {
85-
result = "Argument[" + any(ParameterPosition pos | p = pos.getParameterIn(_)).toString() + "]"
58+
result =
59+
"Argument[" + any(DataFlowImpl::ParameterPosition pos | p = pos.getParameterIn(_)).toString() +
60+
"]"
8661
}
8762

8863
string parameterContentAccess(R::ParamBase p) { result = parameterAccess(p) }
@@ -92,12 +67,12 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
9267
}
9368

9469
bindingset[c]
95-
string paramReturnNodeAsOutput(Callable c, ParameterPosition pos) {
70+
string paramReturnNodeAsOutput(Callable c, DataFlowImpl::ParameterPosition pos) {
9671
result = paramReturnNodeAsContentOutput(c, pos)
9772
}
9873

9974
bindingset[c]
100-
string paramReturnNodeAsContentOutput(Callable c, ParameterPosition pos) {
75+
string paramReturnNodeAsContentOutput(Callable c, DataFlowImpl::ParameterPosition pos) {
10176
result = parameterContentAccess(c.getParamList().getParam(pos.getPosition()))
10277
or
10378
pos.isSelf() and result = qualifierString()
@@ -107,40 +82,51 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
10782
result = ret.(Node::Node).getEnclosingCallable().asCfgScope()
10883
}
10984

110-
predicate isOwnInstanceAccessNode(RustDataFlow::ReturnNode node) {
85+
predicate isOwnInstanceAccessNode(DataFlowImpl::RustDataFlow::ReturnNode node) {
11186
// This is probably not relevant to implement for Rust, as we only use
11287
// `captureMixedFlow` which doesn't explicitly distinguish between
11388
// functions that return `self` and those that don't.
11489
none()
11590
}
11691

117-
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
92+
predicate containerContent(DataFlow::ContentSet c) {
93+
c.(SingletonContentSet).getContent() instanceof ElementContent
94+
}
11895

119-
/**
120-
* Holds if `source` is an API entrypoint, i.e., a source of input where data
121-
* can flow in to a library. This is used for creating sink models, as we
122-
* only want to mark functions as sinks if input to the function can reach
123-
* (from an input source) a known sink.
124-
*/
125-
predicate apiSource(DataFlow::Node source) { source instanceof DataFlow::ParameterNode }
96+
string partialModelRow(Callable api, int i) {
97+
i = 0 and result = api.(Function).getCrateOrigin() // crate
98+
or
99+
i = 1 and result = api.(Function).getExtendedCanonicalPath() // name
100+
}
126101

127-
bindingset[sourceEnclosing, api]
128-
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) { none() }
102+
string partialNeutralModelRow(Callable api, int i) { result = partialModelRow(api, i) }
103+
}
129104

130-
string getInputArgument(DataFlow::Node source) {
131-
result = "Argument[" + source.(Node::SourceParameterNode).getPosition().toString() + "]"
132-
}
105+
private import ModelGeneratorCommonInput
106+
private import MakeModelGeneratorFactory<Location, DataFlowImpl::RustDataFlow, RustTaintTracking, ModelGeneratorCommonInput>
133107

134-
bindingset[kind]
135-
predicate isRelevantSinkKind(string kind) { any() }
108+
private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
109+
class SummaryTargetApi extends Callable {
110+
private Callable lift;
136111

137-
bindingset[kind]
138-
predicate isRelevantSourceKind(string kind) { any() }
112+
SummaryTargetApi() {
113+
lift = this and
114+
relevant(this)
115+
}
139116

140-
predicate containerContent(DataFlow::ContentSet c) {
141-
c.(SingletonContentSet).getContent() instanceof ElementContent
117+
Callable lift() { result = lift }
118+
119+
predicate isRelevant() { relevant(this) }
142120
}
143121

122+
Callable getAsExprEnclosingCallable(NodeExtended node) { result = node.asExpr().getScope() }
123+
124+
Parameter asParameter(NodeExtended node) { result = node.asParameter() }
125+
126+
predicate isUninterestingForDataFlowModels(Callable api) { none() }
127+
128+
predicate isUninterestingForHeuristicDataFlowModels(Callable api) { none() }
129+
144130
predicate isAdditionalContentFlowStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) { none() }
145131

146132
predicate isField(DataFlow::ContentSet c) {
@@ -159,7 +145,7 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
159145
private string encodeContent(ContentSet cs, string arg) {
160146
result = FlowSummary::Input::encodeContent(cs, arg)
161147
or
162-
exists(Content c | cs = TSingletonContentSet(c) |
148+
exists(Content c | cs = DataFlowImpl::TSingletonContentSet(c) |
163149
exists(int pos |
164150
pos = c.(FunctionCallArgumentContent).getPosition() and
165151
result = "Parameter" and
@@ -176,18 +162,47 @@ module ModelGeneratorInput implements ModelGeneratorInputSig<Location, RustDataF
176162
if arg = "" then result = name else result = name + "[" + arg + "]"
177163
)
178164
}
165+
}
179166

180-
string partialModelRow(Callable api, int i) {
181-
i = 0 and result = api.(Function).getCrateOrigin() // crate
182-
or
183-
i = 1 and result = api.(Function).getExtendedCanonicalPath() // name
167+
private module SourceModelGeneratorInput implements SourceModelGeneratorInputSig {
168+
class SourceTargetApi extends Callable {
169+
SourceTargetApi() { relevant(this) }
184170
}
185171

186-
string partialNeutralModelRow(Callable api, int i) { result = partialModelRow(api, i) }
172+
bindingset[sourceEnclosing, api]
173+
predicate irrelevantSourceSinkApi(Callable sourceEnclosing, SourceTargetApi api) { none() }
174+
175+
bindingset[kind]
176+
predicate isRelevantSourceKind(string kind) { any() }
187177

188178
predicate sourceNode(DataFlow::Node node, string kind) { FlowSource::sourceNode(node, kind) }
179+
}
180+
181+
private module SinkModelGeneratorInput implements SinkModelGeneratorInputSig {
182+
class SinkTargetApi extends Callable {
183+
SinkTargetApi() { relevant(this) }
184+
}
185+
186+
predicate sinkModelSanitizer(DataFlow::Node node) { none() }
187+
188+
/**
189+
* Holds if `source` is an API entrypoint, i.e., a source of input where data
190+
* can flow in to a library. This is used for creating sink models, as we
191+
* only want to mark functions as sinks if input to the function can reach
192+
* (from an input source) a known sink.
193+
*/
194+
predicate apiSource(DataFlow::Node source) { source instanceof DataFlow::ParameterNode }
195+
196+
string getInputArgument(DataFlow::Node source) {
197+
result = "Argument[" + source.(Node::SourceParameterNode).getPosition().toString() + "]"
198+
}
199+
200+
bindingset[kind]
201+
predicate isRelevantSinkKind(string kind) { any() }
189202

190203
predicate sinkNode(DataFlow::Node node, string kind) { FlowSink::sinkNode(node, kind) }
191204
}
192205

193-
import MakeModelGenerator<Location, RustDataFlow, RustTaintTracking, ModelGeneratorInput>
206+
import MakeSummaryModelGenerator<SummaryModelGeneratorInput> as SummaryModels
207+
import MakeSourceModelGenerator<SourceModelGeneratorInput> as SourceModels
208+
import MakeSinkModelGenerator<SinkModelGeneratorInput> as SinkModels

rust/ql/src/utils/modelgenerator/internal/CaptureModelsPrinting.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
private import rust as R
22
private import codeql.mad.modelgenerator.internal.ModelPrinting
3-
private import CaptureModels::ModelGeneratorInput as ModelGeneratorInput
3+
private import CaptureModels::ModelGeneratorCommonInput as ModelGeneratorInput
44

55
private module ModelPrintingLang implements ModelPrintingLangSig {
66
class Callable = R::Callable;

rust/ql/test/utils-tests/modelgenerator/CaptureSinkModels.ql

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import rust
22
import utils.modelgenerator.internal.CaptureModels
3+
import SinkModels
34
import utils.test.InlineMadTest
45

56
module InlineMadTestConfig implements InlineMadTestConfigSig {

rust/ql/test/utils-tests/modelgenerator/CaptureSourceModels.ql

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import rust
22
import utils.modelgenerator.internal.CaptureModels
3+
import SourceModels
34
import utils.test.InlineMadTest
45
import codeql.rust.dataflow.internal.ModelsAsData
56

rust/ql/test/utils-tests/modelgenerator/CaptureSummaryModels.ql

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import rust
22
import utils.modelgenerator.internal.CaptureModels
3+
import SummaryModels
34
import utils.test.InlineMadTest
45

56
module InlineMadTestConfig implements InlineMadTestConfigSig {

0 commit comments

Comments
 (0)