Skip to content

Commit 7d65bac

Browse files
committed
Add FlowBarrierGuard to FlowBarrier.qll
1 parent 77cb353 commit 7d65bac

File tree

4 files changed

+164
-3
lines changed

4 files changed

+164
-3
lines changed

rust/ql/lib/codeql/rust/dataflow/FlowBarrier.qll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,27 @@ module FlowBarrier {
5151

5252
final class FlowBarrier = FlowBarrier::Range;
5353

54+
/** Provides the `Range` class used to define the extent of `FlowBarrierGuard`. */
55+
module FlowBarrierGuard {
56+
/** A flow barrier guard. */
57+
abstract class Range extends Impl::Public::BarrierGuardElement {
58+
bindingset[this]
59+
Range() { any() }
60+
61+
override predicate isBarrierGuard(
62+
string input, string branch, string kind, Impl::Public::Provenance provenance, string model
63+
) {
64+
this.isBarrierGuard(input, branch, kind) and provenance = "manual" and model = ""
65+
}
66+
67+
/**
68+
* Holds if this element is a flow barrier guard of kind `kind`, for data
69+
* flowing in as described by `input`, when `this` evaluates to `branch`.
70+
*/
71+
predicate isBarrierGuard(string input, string branch, string kind) { none() }
72+
}
73+
}
74+
75+
final class FlowBarrierGuard = FlowBarrierGuard::Range;
76+
5477
predicate barrierNode = DataFlowImpl::barrierNode/2;

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

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1157,14 +1157,50 @@ 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`. */
1160+
private newtype TKindModelPair =
1161+
TMkPair(string kind, string model) {
1162+
FlowSummaryImpl::Private::barrierGuardSpec(_, _, _, kind, model)
1163+
}
1164+
1165+
private boolean convertAcceptingValue(FlowSummaryImpl::Public::AcceptingValue av) {
1166+
av.isTrue() and result = true
1167+
or
1168+
av.isFalse() and result = false
1169+
// Remaining cases are not supported yet, they depend on the shared Guards library.
1170+
// or
1171+
// av.isNoException() and result.getDualValue().isThrowsException()
1172+
// or
1173+
// av.isZero() and result.asIntValue() = 0
1174+
// or
1175+
// av.isNotZero() and result.getDualValue().asIntValue() = 0
1176+
// or
1177+
// av.isNull() and result.isNullValue()
1178+
// or
1179+
// av.isNotNull() and result.isNonNullValue()
1180+
}
1181+
1182+
private predicate barrierGuardChecks(AstNode g, Expr e, boolean gv, TKindModelPair kmp) {
1183+
exists(
1184+
FlowSummaryImpl::Public::BarrierGuardElement b,
1185+
FlowSummaryImpl::Private::SummaryComponentStack stack,
1186+
FlowSummaryImpl::Public::AcceptingValue acceptingvalue, string kind, string model
1187+
|
1188+
FlowSummaryImpl::Private::barrierGuardSpec(b, stack, acceptingvalue, kind, model) and
1189+
e = FlowSummaryImpl::StepsInput::getSinkNode(b, stack.headOfSingleton()).asExpr() and
1190+
kmp = TMkPair(kind, model) and
1191+
gv = convertAcceptingValue(acceptingvalue) and
1192+
g = b.getCall()
1193+
)
1194+
}
1195+
1196+
/** Holds if `n` is a flow barrier of kind `kind` and model `model`. */
11611197
cached
1162-
predicate barrierNode(Node n, string kind) {
1198+
predicate barrierNode(Node n, string kind, string model) {
11631199
exists(
11641200
FlowSummaryImpl::Public::BarrierElement b,
11651201
FlowSummaryImpl::Private::SummaryComponentStack stack
11661202
|
1167-
FlowSummaryImpl::Private::barrierSpec(b, stack, kind, _)
1203+
FlowSummaryImpl::Private::barrierSpec(b, stack, kind, model)
11681204
|
11691205
n = FlowSummaryImpl::StepsInput::getSourceNode(b, stack, false)
11701206
or
@@ -1174,6 +1210,9 @@ private module Cached {
11741210
.(PostUpdateNode)
11751211
.getPreUpdateNode()
11761212
)
1213+
or
1214+
ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
1215+
model)) = n
11771216
}
11781217

11791218
/**
@@ -1199,3 +1238,34 @@ private module Cached {
11991238
}
12001239

12011240
import Cached
1241+
1242+
/** Holds if `n` is a flow barrier of kind `kind`. */
1243+
predicate barrierNode(Node n, string kind) { barrierNode(n, kind, _) }
1244+
1245+
bindingset[this]
1246+
private signature class ParamSig;
1247+
1248+
private module WithParam<ParamSig P> {
1249+
/**
1250+
* Holds if the guard `g` validates the expression `e` upon evaluating to `gv`.
1251+
*
1252+
* The expression `e` is expected to be a syntactic part of the guard `g`.
1253+
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
1254+
* the argument `x`.
1255+
*/
1256+
signature predicate guardChecksSig(AstNode g, Expr e, boolean branch, P param);
1257+
}
1258+
1259+
/**
1260+
* Provides a set of barrier nodes for a guard that validates an expression.
1261+
*
1262+
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
1263+
* in data flow and taint tracking.
1264+
*/
1265+
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
1266+
/** Gets a node that is safely guarded by the given guard check. */
1267+
Node getABarrierNode(P param) {
1268+
SsaFlow::asNode(result) =
1269+
SsaImpl::DataFlowIntegration::ParameterizedBarrierGuard<P, guardChecks/4>::getABarrierNode(param)
1270+
}
1271+
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,31 @@ private module Cached {
305305

306306
predicate getABarrierNode = getABarrierNodeImpl/0;
307307
}
308+
309+
bindingset[this]
310+
private signature class ParamSig;
311+
312+
private module WithParam<ParamSig P> {
313+
signature predicate guardChecksSig(AstNode g, Expr e, boolean branch, P param);
314+
}
315+
316+
overlay[global]
317+
cached // nothing is actually cached
318+
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
319+
private predicate guardChecksAdjTypes(
320+
DataFlowIntegrationInput::Guard g, DataFlowIntegrationInput::Expr e,
321+
DataFlowIntegrationInput::GuardValue branch, P param
322+
) {
323+
guardChecks(g, e, branch, param)
324+
}
325+
326+
private Node getABarrierNodeImpl(P param) {
327+
result =
328+
DataFlowIntegrationImpl::BarrierGuardWithState<P, guardChecksAdjTypes/4>::getABarrierNode(param)
329+
}
330+
331+
predicate getABarrierNode = getABarrierNodeImpl/1;
332+
}
308333
}
309334
}
310335

shared/dataflow/codeql/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,21 @@ module Make<
381381
abstract predicate isBarrier(string output, string kind, Provenance provenance, string model);
382382
}
383383

384+
/** A barrier guard element. */
385+
abstract class BarrierGuardElement extends SinkBaseFinal {
386+
bindingset[this]
387+
BarrierGuardElement() { any() }
388+
389+
/**
390+
* Holds if this element is a flow barrier guard of kind `kind`, for data
391+
* flowing in as described by `input`, when `this` evaluates to `branch`.
392+
*/
393+
pragma[nomagic]
394+
abstract predicate isBarrierGuard(
395+
string input, string branch, string kind, Provenance provenance, string model
396+
);
397+
}
398+
384399
private signature predicate hasKindSig(string kind);
385400

386401
signature class NeutralCallableSig extends SummarizedCallableBaseFinal {
@@ -748,6 +763,19 @@ module Make<
748763
)
749764
}
750765

766+
private predicate isRelevantBarrierGuard(
767+
BarrierGuardElement e, string input, string branch, string kind, Provenance provenance,
768+
string model
769+
) {
770+
e.isBarrierGuard(input, branch, kind, provenance, model) and
771+
(
772+
provenance.isManual()
773+
or
774+
provenance.isGenerated() and
775+
not exists(Provenance p | p.isManual() and e.isBarrierGuard(_, _, kind, p, _))
776+
)
777+
}
778+
751779
private predicate flowSpec(string spec) {
752780
exists(SummarizedCallable c |
753781
c.propagatesFlow(spec, _, _, _, _, _)
@@ -759,6 +787,8 @@ module Make<
759787
or
760788
isRelevantBarrier(_, spec, _, _, _)
761789
or
790+
isRelevantBarrierGuard(_, spec, _, _, _, _)
791+
or
762792
isRelevantSink(_, spec, _, _, _)
763793
}
764794

@@ -1554,6 +1584,19 @@ module Make<
15541584
)
15551585
}
15561586

1587+
/**
1588+
* Holds if `barrierGuard` is a relevant barrier guard element with input specification `inSpec`.
1589+
*/
1590+
predicate barrierGuardSpec(
1591+
BarrierGuardElement barrierGuard, SummaryComponentStack inSpec, string branch, string kind,
1592+
string model
1593+
) {
1594+
exists(string input |
1595+
isRelevantBarrierGuard(barrierGuard, input, branch, kind, _, model) and
1596+
External::interpretSpec(input, inSpec)
1597+
)
1598+
}
1599+
15571600
signature module TypesInputSig {
15581601
/** Gets the type of content `c`. */
15591602
DataFlowType getContentType(ContentSet c);

0 commit comments

Comments
 (0)