Skip to content

Commit 5a91b94

Browse files
committed
Refactor using OptionalStep
1 parent d3e2877 commit 5a91b94

File tree

14 files changed

+135
-43
lines changed

14 files changed

+135
-43
lines changed

rust/ql/integration-tests/hello-project/summary.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| Macro calls - resolved | 2 |
1616
| Macro calls - total | 2 |
1717
| Macro calls - unresolved | 0 |
18-
| Taint edges - number of edges | 1675 |
18+
| Taint edges - number of edges | 1674 |
1919
| Taint reach - nodes tainted | 0 |
2020
| Taint reach - per million nodes | 0 |
2121
| Taint sinks - cryptographic operations | 0 |

rust/ql/integration-tests/hello-workspace/summary.cargo.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| Macro calls - resolved | 2 |
1616
| Macro calls - total | 2 |
1717
| Macro calls - unresolved | 0 |
18-
| Taint edges - number of edges | 1675 |
18+
| Taint edges - number of edges | 1674 |
1919
| Taint reach - nodes tainted | 0 |
2020
| Taint reach - per million nodes | 0 |
2121
| Taint sinks - cryptographic operations | 0 |

rust/ql/integration-tests/hello-workspace/summary.rust-project.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
| Macro calls - resolved | 2 |
1616
| Macro calls - total | 2 |
1717
| Macro calls - unresolved | 0 |
18-
| Taint edges - number of edges | 1675 |
18+
| Taint edges - number of edges | 1674 |
1919
| Taint reach - nodes tainted | 0 |
2020
| Taint reach - per million nodes | 0 |
2121
| Taint sinks - cryptographic operations | 0 |

rust/ql/lib/codeql/rust/dataflow/internal/Content.qll

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,41 @@ final class SingletonContentSet extends ContentSet, TSingletonContentSet {
214214
override Content getAReadContent() { result = c }
215215
}
216216

217+
/**
218+
* A step in a flow summary defined using `OptionalStep[name]`. An `OptionalStep` is "opt-in", which means
219+
* that by default the step is not present in the flow summary and needs to be explicitly enabled by defining
220+
* an additional flow step.
221+
*/
222+
final class OptionalStep extends ContentSet, TOptionalStep {
223+
override string toString() {
224+
exists(string name |
225+
this = TOptionalStep(name) and
226+
result = "OptionalStep[" + name + "]"
227+
)
228+
}
229+
230+
override Content getAStoreContent() { none() }
231+
232+
override Content getAReadContent() { none() }
233+
}
234+
235+
/**
236+
* A step in a flow summary defined using `OptionalBarrier[name]`. An `OptionalBarrier` is "opt-out", by default
237+
* data can flow freely through the step. Flow through the step can be explicity blocked by defining its node as a barrier.
238+
*/
239+
final class OptionalBarrier extends ContentSet, TOptionalBarrier {
240+
override string toString() {
241+
exists(string name |
242+
this = TOptionalBarrier(name) and
243+
result = "OptionalBarrier[" + name + "]"
244+
)
245+
}
246+
247+
override Content getAStoreContent() { none() }
248+
249+
override Content getAReadContent() { none() }
250+
}
251+
217252
private import codeql.rust.internal.CachedStages
218253

219254
cached

rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,12 @@ module RustDataFlow implements InputSig<Location> {
581581
model = ""
582582
or
583583
LocalFlow::flowSummaryLocalStep(nodeFrom, nodeTo, model)
584+
or
585+
// Add flow through optional barriers. This step is then blocked by the barrier for queries that choose to use the barrier.
586+
FlowSummaryImpl::Private::Steps::summaryReadStep(nodeFrom
587+
.(Node::FlowSummaryNode)
588+
.getSummaryNode(), TOptionalBarrier(_), nodeTo.(Node::FlowSummaryNode).getSummaryNode()) and
589+
model = ""
584590
}
585591

586592
/**
@@ -710,7 +716,8 @@ module RustDataFlow implements InputSig<Location> {
710716
)
711717
or
712718
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), cs,
713-
node2.(FlowSummaryNode).getSummaryNode())
719+
node2.(FlowSummaryNode).getSummaryNode()) and
720+
not isSpecialContentSet(cs)
714721
}
715722

716723
pragma[nomagic]
@@ -807,7 +814,8 @@ module RustDataFlow implements InputSig<Location> {
807814
storeContentStep(node1, cs.(SingletonContentSet).getContent(), node2)
808815
or
809816
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), cs,
810-
node2.(FlowSummaryNode).getSummaryNode())
817+
node2.(FlowSummaryNode).getSummaryNode()) and
818+
not isSpecialContentSet(cs)
811819
}
812820

813821
/**
@@ -1093,7 +1101,24 @@ private module Cached {
10931101
newtype TReturnKind = TNormalReturnKind()
10941102

10951103
cached
1096-
newtype TContentSet = TSingletonContentSet(Content c)
1104+
newtype TContentSet =
1105+
TSingletonContentSet(Content c) or
1106+
TOptionalStep(string name) {
1107+
name = any(FlowSummaryImpl::Private::AccessPathToken tok).getAnArgument("OptionalStep")
1108+
} or
1109+
TOptionalBarrier(string name) {
1110+
name = any(FlowSummaryImpl::Private::AccessPathToken tok).getAnArgument("OptionalBarrier")
1111+
}
1112+
1113+
/**
1114+
* Holds if `cs` is used to encode a special operation as a content component, but should not
1115+
* be treated as an ordinary content component.
1116+
*/
1117+
cached
1118+
predicate isSpecialContentSet(ContentSet cs) {
1119+
cs instanceof TOptionalStep or
1120+
cs instanceof TOptionalBarrier
1121+
}
10971122

10981123
/** Holds if `n` is a flow source of kind `kind`. */
10991124
cached
@@ -1105,3 +1130,31 @@ private module Cached {
11051130
}
11061131

11071132
import Cached
1133+
1134+
cached
1135+
private module OptionalSteps {
1136+
/**
1137+
* A step in a flow summary defined using `OptionalStep[name]`. An `OptionalStep` is "opt-in", which means
1138+
* that by default the step is not present in the flow summary and needs to be explicitly enabled by defining
1139+
* an additional flow step.
1140+
*/
1141+
cached
1142+
predicate optionalStep(Node node1, string name, Node node2) {
1143+
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(),
1144+
TOptionalStep(name), node2.(FlowSummaryNode).getSummaryNode()) or
1145+
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(),
1146+
TOptionalStep(name), node2.(FlowSummaryNode).getSummaryNode())
1147+
}
1148+
1149+
/**
1150+
* A step in a flow summary defined using `OptionalBarrier[name]`. An `OptionalBarrier` is "opt-out", by default
1151+
* data can flow freely through the step. Flow through the step can be explicity blocked by defining its node as a barrier.
1152+
*/
1153+
cached
1154+
predicate optionalBarrier(Node node, string name) {
1155+
FlowSummaryImpl::Private::Steps::summaryReadStep(_, TOptionalBarrier(name),
1156+
node.(FlowSummaryNode).getSummaryNode())
1157+
}
1158+
}
1159+
1160+
import OptionalSteps

rust/ql/lib/codeql/rust/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ module Input implements InputSig<Location, RustDataFlow> {
5454

5555
RustDataFlow::ArgumentPosition callbackSelfParameterPosition() { result.isClosureSelf() }
5656

57-
ReturnKind getStandardReturnValueKind() { result = TNormalReturnKind() }
57+
ReturnKind getStandardReturnValueKind() { result = TNormalReturnKind() and Stage::ref() }
5858

5959
string encodeParameterPosition(ParameterPosition pos) { result = pos.toString() }
6060

@@ -105,6 +105,10 @@ module Input implements InputSig<Location, RustDataFlow> {
105105
c = TFutureContent() and
106106
arg = ""
107107
)
108+
or
109+
cs = TOptionalStep(arg) and result = "OptionalStep"
110+
or
111+
cs = TOptionalBarrier(arg) and result = "OptionalBarrier"
108112
}
109113

110114
string encodeReturn(ReturnKind rk, string arg) { none() }
@@ -193,3 +197,12 @@ module ParsePositions {
193197
i = AccessPath::parseInt(c)
194198
}
195199
}
200+
201+
cached
202+
module Stage {
203+
cached
204+
predicate ref() { 1 = 1 }
205+
206+
cached
207+
predicate backref() { optionalStep(_, _, _) }
208+
}

rust/ql/lib/codeql/rust/dataflow/internal/TaintTrackingImpl.qll

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ module RustTaintTracking implements InputSig<Location, RustDataFlow> {
6969
exists(Content c | c = cs.(SingletonContentSet).getContent() |
7070
c instanceof ElementContent or
7171
c instanceof ReferenceContent
72-
)
72+
) and
73+
// Optional steps are added through isAdditionalFlowStep but we don't want the implicit reads
74+
not optionalStep(node, _, _)
7375
}
7476

7577
/**

rust/ql/lib/codeql/rust/frameworks/stdlib/Stdlib.qll

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,3 @@ private class StartswithCall extends Path::SafeAccessCheck::Range, CfgNodes::Met
2121
branch = true
2222
}
2323
}
24-
25-
/**
26-
* A call to `Path.canonicalize`.
27-
* See https://doc.rust-lang.org/std/path/struct.Path.html#method.canonicalize
28-
*/
29-
private class PathCanonicalizeCall extends Path::PathNormalization::Range {
30-
CfgNodes::MethodCallExprCfgNode call;
31-
32-
PathCanonicalizeCall() {
33-
call = this.asExpr() and
34-
call.getAstNode().(Resolvable).getResolvedPath() = "<crate::path::Path>::canonicalize"
35-
}
36-
37-
override DataFlow::Node getPathArg() { result.asExpr() = call.getReceiver() }
38-
}

rust/ql/lib/codeql/rust/frameworks/stdlib/fs.model.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ extensions:
1616
- ["lang:std", "<crate::path::PathBuf as crate::convert::From>::from", "Argument[0]", "ReturnValue", "taint", "manual"]
1717
- ["lang:std", "<crate::path::Path>::join", "Argument[self]", "ReturnValue", "taint", "manual"]
1818
- ["lang:std", "<crate::path::Path>::join", "Argument[0]", "ReturnValue", "taint", "manual"]
19+
- ["lang:std", "<crate::path::Path>::canonicalize", "Argument[self]", "ReturnValue.Field[crate::result::Result::Ok(0)].OptionalStep[normalize-path]", "taint", "manual"]
1920
- ["lang:std", "<crate::path::Path>::canonicalize", "Argument[self]", "ReturnValue.Field[crate::result::Result::Ok(0)]", "taint", "manual"]

rust/ql/lib/codeql/rust/frameworks/stdlib/lang-core.model.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,3 @@ extensions:
3232
- ["lang:alloc", "<crate::string::String>::as_str", "Argument[self]", "ReturnValue", "taint", "manual"]
3333
- ["lang:alloc", "<crate::string::String>::as_bytes", "Argument[self]", "ReturnValue", "taint", "manual"]
3434
- ["lang:alloc", "<_ as crate::string::ToString>::to_string", "Argument[self]", "ReturnValue", "taint", "manual"]
35-
# Result
36-
- ["lang:core", "<crate::result::Result>::unwrap", "Argument[self]", "ReturnValue", "taint", "manual"]
37-

0 commit comments

Comments
 (0)