Skip to content

Commit d3177b9

Browse files
committed
Add FlowBarrier.qll
1 parent f455054 commit d3177b9

File tree

3 files changed

+87
-5
lines changed

3 files changed

+87
-5
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/**
2+
* Provides classes and predicates for defining barriers.
3+
*
4+
* Flow barriers defined here feed into data flow configurations as follows:
5+
*
6+
* ```text
7+
* data from *.model.yml | QL extensions of FlowBarrier::Range
8+
* v v
9+
* FlowBarrier (associated with a models-as-data kind string)
10+
* v
11+
* barrierNode predicate | other QL defined barriers, for example using concepts
12+
* v v
13+
* various Barrier classes for specific data flow configurations <- extending QueryBarrier
14+
* ```
15+
*
16+
* New barriers should be defined using models-as-data, QL extensions of
17+
* `FlowBarrier::Range`, or concepts. Data flow configurations should use the
18+
* `barrierNode` predicate and/or concepts to define their barriers.
19+
*/
20+
21+
private import rust
22+
private import internal.FlowSummaryImpl as Impl
23+
private import internal.DataFlowImpl as DataFlowImpl
24+
25+
// import all instances below
26+
private module Barriers {
27+
private import codeql.rust.Frameworks
28+
private import codeql.rust.dataflow.internal.ModelsAsData
29+
}
30+
31+
/** Provides the `Range` class used to define the extent of `FlowBarrier`. */
32+
module FlowBarrier {
33+
/** A flow barrier. */
34+
abstract class Range extends Impl::Public::BarrierElement {
35+
bindingset[this]
36+
Range() { any() }
37+
38+
override predicate isBarrier(
39+
string output, string kind, Impl::Public::Provenance provenance, string model
40+
) {
41+
this.isBarrier(output, kind) and provenance = "manual" and model = ""
42+
}
43+
44+
/**
45+
* Holds if this element is a flow barrier of kind `kind`, where data
46+
* flows out as described by `output`.
47+
*/
48+
predicate isBarrier(string output, string kind) { none() }
49+
}
50+
}
51+
52+
final class FlowBarrier = FlowBarrier::Range;
53+
54+
predicate barrierNode = DataFlowImpl::barrierNode/2;

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,25 @@ private module Cached {
11571157
cached
11581158
predicate sinkNode(Node n, string kind) { n.(FlowSummaryNode).isSink(kind, _) }
11591159

1160+
/** Holds if `n` is a flow barrier of kind `kind`. */
1161+
cached
1162+
predicate barrierNode(Node n, string kind) {
1163+
exists(
1164+
FlowSummaryImpl::Public::BarrierElement b,
1165+
FlowSummaryImpl::Private::SummaryComponentStack stack
1166+
|
1167+
FlowSummaryImpl::Private::barrierSpec(b, stack, kind, _)
1168+
|
1169+
n = FlowSummaryImpl::StepsInput::getSourceNode(b, stack, false)
1170+
or
1171+
// For barriers like `Argument[0]` we want to target the pre-update node
1172+
n =
1173+
FlowSummaryImpl::StepsInput::getSourceNode(b, stack, true)
1174+
.(PostUpdateNode)
1175+
.getPreUpdateNode()
1176+
)
1177+
}
1178+
11601179
/**
11611180
* A step in a flow summary defined using `OptionalStep[name]`. An `OptionalStep` is "opt-in", which means
11621181
* that by default the step is not present in the flow summary and needs to be explicitly enabled by defining

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

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ module Input implements InputSig<Location, RustDataFlow> {
143143

144144
private import Make<Location, RustDataFlow, Input> as Impl
145145

146-
private module StepsInput implements Impl::Private::StepsInputSig {
146+
module StepsInput implements Impl::Private::StepsInputSig {
147147
DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc }
148148

149149
/** Gets the argument of `source` described by `sc`, if any. */
@@ -171,18 +171,27 @@ private module StepsInput implements Impl::Private::StepsInputSig {
171171
result.asCfgScope() = source.getEnclosingCfgScope()
172172
}
173173

174-
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
174+
additional RustDataFlow::Node getSourceNode(
175+
Input::SourceBase source, Impl::Private::SummaryComponentStack s, boolean isArgPostUpdate
176+
) {
175177
s.head() = Impl::Private::SummaryComponent::return(_) and
176-
result.asExpr() = source.getCall()
178+
result.asExpr() = source.getCall() and
179+
isArgPostUpdate = false
177180
or
178181
exists(RustDataFlow::ArgumentPosition pos, Expr arg |
179182
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
180183
arg = getSourceNodeArgument(source, s.tail().headOfSingleton()) and
181-
result.asParameter() = getCallable(arg).getParam(pos.getPosition())
184+
result.asParameter() = getCallable(arg).getParam(pos.getPosition()) and
185+
isArgPostUpdate = false
182186
)
183187
or
184188
result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr() =
185-
getSourceNodeArgument(source, s.headOfSingleton())
189+
getSourceNodeArgument(source, s.headOfSingleton()) and
190+
isArgPostUpdate = true
191+
}
192+
193+
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
194+
result = getSourceNode(source, s, _)
186195
}
187196

188197
RustDataFlow::Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) {

0 commit comments

Comments
 (0)