mirror of
https://github.com/github/codeql.git
synced 2026-04-22 07:15:15 +02:00
Add FlowBarrier.qll
This commit is contained in:
54
rust/ql/lib/codeql/rust/dataflow/FlowBarrier.qll
Normal file
54
rust/ql/lib/codeql/rust/dataflow/FlowBarrier.qll
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Provides classes and predicates for defining barriers.
|
||||
*
|
||||
* Flow barriers defined here feed into data flow configurations as follows:
|
||||
*
|
||||
* ```text
|
||||
* data from *.model.yml | QL extensions of FlowBarrier::Range
|
||||
* v v
|
||||
* FlowBarrier (associated with a models-as-data kind string)
|
||||
* v
|
||||
* barrierNode predicate | other QL defined barriers, for example using concepts
|
||||
* v v
|
||||
* various Barrier classes for specific data flow configurations <- extending QueryBarrier
|
||||
* ```
|
||||
*
|
||||
* New barriers should be defined using models-as-data, QL extensions of
|
||||
* `FlowBarrier::Range`, or concepts. Data flow configurations should use the
|
||||
* `barrierNode` predicate and/or concepts to define their barriers.
|
||||
*/
|
||||
|
||||
private import rust
|
||||
private import internal.FlowSummaryImpl as Impl
|
||||
private import internal.DataFlowImpl as DataFlowImpl
|
||||
|
||||
// import all instances below
|
||||
private module Barriers {
|
||||
private import codeql.rust.Frameworks
|
||||
private import codeql.rust.dataflow.internal.ModelsAsData
|
||||
}
|
||||
|
||||
/** Provides the `Range` class used to define the extent of `FlowBarrier`. */
|
||||
module FlowBarrier {
|
||||
/** A flow barrier. */
|
||||
abstract class Range extends Impl::Public::BarrierElement {
|
||||
bindingset[this]
|
||||
Range() { any() }
|
||||
|
||||
override predicate isBarrier(
|
||||
string output, string kind, Impl::Public::Provenance provenance, string model
|
||||
) {
|
||||
this.isBarrier(output, kind) and provenance = "manual" and model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is a flow barrier of kind `kind`, where data
|
||||
* flows out as described by `output`.
|
||||
*/
|
||||
predicate isBarrier(string output, string kind) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
final class FlowBarrier = FlowBarrier::Range;
|
||||
|
||||
predicate barrierNode = DataFlowImpl::barrierNode/2;
|
||||
@@ -1157,6 +1157,25 @@ private module Cached {
|
||||
cached
|
||||
predicate sinkNode(Node n, string kind) { n.(FlowSummaryNode).isSink(kind, _) }
|
||||
|
||||
/** Holds if `n` is a flow barrier of kind `kind`. */
|
||||
cached
|
||||
predicate barrierNode(Node n, string kind) {
|
||||
exists(
|
||||
FlowSummaryImpl::Public::BarrierElement b,
|
||||
FlowSummaryImpl::Private::SummaryComponentStack stack
|
||||
|
|
||||
FlowSummaryImpl::Private::barrierSpec(b, stack, kind, _)
|
||||
|
|
||||
n = FlowSummaryImpl::StepsInput::getSourceNode(b, stack, false)
|
||||
or
|
||||
// For barriers like `Argument[0]` we want to target the pre-update node
|
||||
n =
|
||||
FlowSummaryImpl::StepsInput::getSourceNode(b, stack, true)
|
||||
.(PostUpdateNode)
|
||||
.getPreUpdateNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A step in a flow summary defined using `OptionalStep[name]`. An `OptionalStep` is "opt-in", which means
|
||||
* that by default the step is not present in the flow summary and needs to be explicitly enabled by defining
|
||||
|
||||
@@ -143,7 +143,7 @@ module Input implements InputSig<Location, RustDataFlow> {
|
||||
|
||||
private import Make<Location, RustDataFlow, Input> as Impl
|
||||
|
||||
private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
module StepsInput implements Impl::Private::StepsInputSig {
|
||||
DataFlowCall getACall(Public::SummarizedCallable sc) { result.asCall().getStaticTarget() = sc }
|
||||
|
||||
/** Gets the argument of `source` described by `sc`, if any. */
|
||||
@@ -171,18 +171,27 @@ private module StepsInput implements Impl::Private::StepsInputSig {
|
||||
result.asCfgScope() = source.getEnclosingCfgScope()
|
||||
}
|
||||
|
||||
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
|
||||
additional RustDataFlow::Node getSourceNode(
|
||||
Input::SourceBase source, Impl::Private::SummaryComponentStack s, boolean isArgPostUpdate
|
||||
) {
|
||||
s.head() = Impl::Private::SummaryComponent::return(_) and
|
||||
result.asExpr() = source.getCall()
|
||||
result.asExpr() = source.getCall() and
|
||||
isArgPostUpdate = false
|
||||
or
|
||||
exists(RustDataFlow::ArgumentPosition pos, Expr arg |
|
||||
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
|
||||
arg = getSourceNodeArgument(source, s.tail().headOfSingleton()) and
|
||||
result.asParameter() = getCallable(arg).getParam(pos.getPosition())
|
||||
result.asParameter() = getCallable(arg).getParam(pos.getPosition()) and
|
||||
isArgPostUpdate = false
|
||||
)
|
||||
or
|
||||
result.(RustDataFlow::PostUpdateNode).getPreUpdateNode().asExpr() =
|
||||
getSourceNodeArgument(source, s.headOfSingleton())
|
||||
getSourceNodeArgument(source, s.headOfSingleton()) and
|
||||
isArgPostUpdate = true
|
||||
}
|
||||
|
||||
RustDataFlow::Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
|
||||
result = getSourceNode(source, s, _)
|
||||
}
|
||||
|
||||
RustDataFlow::Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) {
|
||||
|
||||
Reference in New Issue
Block a user