mirror of
https://github.com/github/codeql.git
synced 2026-03-31 12:48:17 +02:00
Add FlowBarrierGuard to FlowBarrier.qll
This commit is contained in:
@@ -51,4 +51,27 @@ module FlowBarrier {
|
||||
|
||||
final class FlowBarrier = FlowBarrier::Range;
|
||||
|
||||
/** Provides the `Range` class used to define the extent of `FlowBarrierGuard`. */
|
||||
module FlowBarrierGuard {
|
||||
/** A flow barrier guard. */
|
||||
abstract class Range extends Impl::Public::BarrierGuardElement {
|
||||
bindingset[this]
|
||||
Range() { any() }
|
||||
|
||||
override predicate isBarrierGuard(
|
||||
string input, string branch, string kind, Impl::Public::Provenance provenance, string model
|
||||
) {
|
||||
this.isBarrierGuard(input, branch, kind) and provenance = "manual" and model = ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this element is a flow barrier guard of kind `kind`, for data
|
||||
* flowing in as described by `input`, when `this` evaluates to `branch`.
|
||||
*/
|
||||
predicate isBarrierGuard(string input, string branch, string kind) { none() }
|
||||
}
|
||||
}
|
||||
|
||||
final class FlowBarrierGuard = FlowBarrierGuard::Range;
|
||||
|
||||
predicate barrierNode = DataFlowImpl::barrierNode/2;
|
||||
|
||||
@@ -1157,14 +1157,50 @@ private module Cached {
|
||||
cached
|
||||
predicate sinkNode(Node n, string kind) { n.(FlowSummaryNode).isSink(kind, _) }
|
||||
|
||||
/** Holds if `n` is a flow barrier of kind `kind`. */
|
||||
private newtype TKindModelPair =
|
||||
TMkPair(string kind, string model) {
|
||||
FlowSummaryImpl::Private::barrierGuardSpec(_, _, _, kind, model)
|
||||
}
|
||||
|
||||
private boolean convertAcceptingValue(FlowSummaryImpl::Public::AcceptingValue av) {
|
||||
av.isTrue() and result = true
|
||||
or
|
||||
av.isFalse() and result = false
|
||||
// Remaining cases are not supported yet, they depend on the shared Guards library.
|
||||
// or
|
||||
// av.isNoException() and result.getDualValue().isThrowsException()
|
||||
// or
|
||||
// av.isZero() and result.asIntValue() = 0
|
||||
// or
|
||||
// av.isNotZero() and result.getDualValue().asIntValue() = 0
|
||||
// or
|
||||
// av.isNull() and result.isNullValue()
|
||||
// or
|
||||
// av.isNotNull() and result.isNonNullValue()
|
||||
}
|
||||
|
||||
private predicate barrierGuardChecks(AstNode g, Expr e, boolean gv, TKindModelPair kmp) {
|
||||
exists(
|
||||
FlowSummaryImpl::Public::BarrierGuardElement b,
|
||||
FlowSummaryImpl::Private::SummaryComponentStack stack,
|
||||
FlowSummaryImpl::Public::AcceptingValue acceptingvalue, string kind, string model
|
||||
|
|
||||
FlowSummaryImpl::Private::barrierGuardSpec(b, stack, acceptingvalue, kind, model) and
|
||||
e = FlowSummaryImpl::StepsInput::getSinkNode(b, stack.headOfSingleton()).asExpr() and
|
||||
kmp = TMkPair(kind, model) and
|
||||
gv = convertAcceptingValue(acceptingvalue) and
|
||||
g = b.getCall()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `n` is a flow barrier of kind `kind` and model `model`. */
|
||||
cached
|
||||
predicate barrierNode(Node n, string kind) {
|
||||
predicate barrierNode(Node n, string kind, string model) {
|
||||
exists(
|
||||
FlowSummaryImpl::Public::BarrierElement b,
|
||||
FlowSummaryImpl::Private::SummaryComponentStack stack
|
||||
|
|
||||
FlowSummaryImpl::Private::barrierSpec(b, stack, kind, _)
|
||||
FlowSummaryImpl::Private::barrierSpec(b, stack, kind, model)
|
||||
|
|
||||
n = FlowSummaryImpl::StepsInput::getSourceNode(b, stack, false)
|
||||
or
|
||||
@@ -1174,6 +1210,9 @@ private module Cached {
|
||||
.(PostUpdateNode)
|
||||
.getPreUpdateNode()
|
||||
)
|
||||
or
|
||||
ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
|
||||
model)) = n
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1199,3 +1238,34 @@ private module Cached {
|
||||
}
|
||||
|
||||
import Cached
|
||||
|
||||
/** Holds if `n` is a flow barrier of kind `kind`. */
|
||||
predicate barrierNode(Node n, string kind) { barrierNode(n, kind, _) }
|
||||
|
||||
bindingset[this]
|
||||
private signature class ParamSig;
|
||||
|
||||
private module WithParam<ParamSig P> {
|
||||
/**
|
||||
* Holds if the guard `g` validates the expression `e` upon evaluating to `gv`.
|
||||
*
|
||||
* The expression `e` is expected to be a syntactic part of the guard `g`.
|
||||
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
|
||||
* the argument `x`.
|
||||
*/
|
||||
signature predicate guardChecksSig(AstNode g, Expr e, boolean branch, P param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a set of barrier nodes for a guard that validates an expression.
|
||||
*
|
||||
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
|
||||
* in data flow and taint tracking.
|
||||
*/
|
||||
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
|
||||
/** Gets a node that is safely guarded by the given guard check. */
|
||||
Node getABarrierNode(P param) {
|
||||
SsaFlow::asNode(result) =
|
||||
SsaImpl::DataFlowIntegration::ParameterizedBarrierGuard<P, guardChecks/4>::getABarrierNode(param)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -305,6 +305,31 @@ private module Cached {
|
||||
|
||||
predicate getABarrierNode = getABarrierNodeImpl/0;
|
||||
}
|
||||
|
||||
bindingset[this]
|
||||
private signature class ParamSig;
|
||||
|
||||
private module WithParam<ParamSig P> {
|
||||
signature predicate guardChecksSig(AstNode g, Expr e, boolean branch, P param);
|
||||
}
|
||||
|
||||
overlay[global]
|
||||
cached // nothing is actually cached
|
||||
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
|
||||
private predicate guardChecksAdjTypes(
|
||||
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e,
|
||||
DataFlowIntegrationInput::GuardValue branch, P param
|
||||
) {
|
||||
guardChecks(g, e, branch, param)
|
||||
}
|
||||
|
||||
private Node getABarrierNodeImpl(P param) {
|
||||
result =
|
||||
DataFlowIntegrationImpl::BarrierGuardWithState<P, guardChecksAdjTypes/4>::getABarrierNode(param)
|
||||
}
|
||||
|
||||
predicate getABarrierNode = getABarrierNodeImpl/1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -381,6 +381,21 @@ module Make<
|
||||
abstract predicate isBarrier(string output, string kind, Provenance provenance, string model);
|
||||
}
|
||||
|
||||
/** A barrier guard element. */
|
||||
abstract class BarrierGuardElement extends SinkBaseFinal {
|
||||
bindingset[this]
|
||||
BarrierGuardElement() { any() }
|
||||
|
||||
/**
|
||||
* Holds if this element is a flow barrier guard of kind `kind`, for data
|
||||
* flowing in as described by `input`, when `this` evaluates to `branch`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
abstract predicate isBarrierGuard(
|
||||
string input, string branch, string kind, Provenance provenance, string model
|
||||
);
|
||||
}
|
||||
|
||||
private signature predicate hasKindSig(string kind);
|
||||
|
||||
signature class NeutralCallableSig extends SummarizedCallableBaseFinal {
|
||||
@@ -748,6 +763,19 @@ module Make<
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isRelevantBarrierGuard(
|
||||
BarrierGuardElement e, string input, string branch, string kind, Provenance provenance,
|
||||
string model
|
||||
) {
|
||||
e.isBarrierGuard(input, branch, kind, provenance, model) and
|
||||
(
|
||||
provenance.isManual()
|
||||
or
|
||||
provenance.isGenerated() and
|
||||
not exists(Provenance p | p.isManual() and e.isBarrierGuard(_, _, kind, p, _))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate flowSpec(string spec) {
|
||||
exists(SummarizedCallable c |
|
||||
c.propagatesFlow(spec, _, _, _, _, _)
|
||||
@@ -759,6 +787,8 @@ module Make<
|
||||
or
|
||||
isRelevantBarrier(_, spec, _, _, _)
|
||||
or
|
||||
isRelevantBarrierGuard(_, spec, _, _, _, _)
|
||||
or
|
||||
isRelevantSink(_, spec, _, _, _)
|
||||
}
|
||||
|
||||
@@ -1554,6 +1584,19 @@ module Make<
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `barrierGuard` is a relevant barrier guard element with input specification `inSpec`.
|
||||
*/
|
||||
predicate barrierGuardSpec(
|
||||
BarrierGuardElement barrierGuard, SummaryComponentStack inSpec, string branch, string kind,
|
||||
string model
|
||||
) {
|
||||
exists(string input |
|
||||
isRelevantBarrierGuard(barrierGuard, input, branch, kind, _, model) and
|
||||
External::interpretSpec(input, inSpec)
|
||||
)
|
||||
}
|
||||
|
||||
signature module TypesInputSig {
|
||||
/** Gets the type of content `c`. */
|
||||
DataFlowType getContentType(ContentSet c);
|
||||
|
||||
Reference in New Issue
Block a user