Skip to content

Commit 000f2c3

Browse files
authored
Merge pull request #21001 from aschackmull/guards/generalise-validationwrapper
Guards: Generalise ValidationWrapper to support GuardValue-based BarrierGuards
2 parents cd721b8 + eaa9686 commit 000f2c3

File tree

6 files changed

+92
-32
lines changed

6 files changed

+92
-32
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImpl.qll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1051,21 +1051,21 @@ module BarrierGuardWithIntParam<guardChecksNodeSig/4 guardChecksNode> {
10511051
}
10521052

10531053
private predicate guardChecksInstr(
1054-
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, boolean branch,
1054+
IRGuards::Guards_v1::Guard g, IRGuards::GuardsInput::Expr instr, IRGuards::GuardValue gv,
10551055
int indirectionIndex
10561056
) {
10571057
exists(Node node |
10581058
nodeHasInstruction(node, instr, indirectionIndex) and
1059-
guardChecksNode(g, node, branch, indirectionIndex)
1059+
guardChecksNode(g, node, gv.asBooleanValue(), indirectionIndex)
10601060
)
10611061
}
10621062

10631063
private predicate guardChecksWithWrappers(
10641064
DataFlowIntegrationInput::Guard g, SsaImpl::Definition def, IRGuards::GuardValue val,
10651065
int indirectionIndex
10661066
) {
1067-
IRGuards::Guards_v1::ValidationWrapperWithState<int, guardChecksInstr/4>::guardChecksDef(g, def,
1068-
val, indirectionIndex)
1067+
IRGuards::Guards_v1::ParameterizedValidationWrapper<int, guardChecksInstr/4>::guardChecksDef(g,
1068+
def, val, indirectionIndex)
10691069
}
10701070

10711071
Node getABarrierNode(int indirectionIndex) {

java/ql/lib/semmle/code/java/dataflow/internal/DataFlowUtil.qll

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -375,24 +375,48 @@ class ContentSet instanceof Content {
375375
}
376376

377377
/**
378-
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
378+
* Holds if the guard `g` validates the expression `e` upon evaluating to `gv`.
379379
*
380380
* The expression `e` is expected to be a syntactic part of the guard `g`.
381381
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
382382
* the argument `x`.
383383
*/
384-
signature predicate guardChecksSig(Guard g, Expr e, boolean branch);
384+
signature predicate valueGuardChecksSig(Guard g, Expr e, GuardValue gv);
385385

386386
/**
387387
* Provides a set of barrier nodes for a guard that validates an expression.
388388
*
389389
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
390390
* in data flow and taint tracking.
391391
*/
392-
module BarrierGuard<guardChecksSig/3 guardChecks> {
392+
module BarrierGuardValue<valueGuardChecksSig/3 guardChecks> {
393393
/** Gets a node that is safely guarded by the given guard check. */
394394
Node getABarrierNode() {
395395
SsaFlow::asNode(result) =
396396
SsaImpl::DataFlowIntegration::BarrierGuard<guardChecks/3>::getABarrierNode()
397397
}
398398
}
399+
400+
/**
401+
* Holds if the guard `g` validates the expression `e` upon evaluating to `branch`.
402+
*
403+
* The expression `e` is expected to be a syntactic part of the guard `g`.
404+
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
405+
* the argument `x`.
406+
*/
407+
signature predicate guardChecksSig(Guard g, Expr e, boolean branch);
408+
409+
/**
410+
* Provides a set of barrier nodes for a guard that validates an expression.
411+
*
412+
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
413+
* in data flow and taint tracking.
414+
*/
415+
module BarrierGuard<guardChecksSig/3 guardChecks> {
416+
private predicate guardChecks0(Guard g, Expr e, GuardValue gv) {
417+
guardChecks(g, e, gv.asBooleanValue())
418+
}
419+
420+
/** Gets a node that is safely guarded by the given guard check. */
421+
Node getABarrierNode() { result = BarrierGuardValue<guardChecks0/3>::getABarrierNode() }
422+
}

java/ql/lib/semmle/code/java/dataflow/internal/SsaImpl.qll

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -564,12 +564,14 @@ private module Cached {
564564
DataFlowIntegrationImpl::localMustFlowStep(v, nodeFrom, nodeTo)
565565
}
566566

567-
signature predicate guardChecksSig(Guards::Guard g, Expr e, boolean branch);
567+
signature predicate guardChecksSig(Guards::Guard g, Expr e, Guards::GuardValue gv);
568568

569569
cached // nothing is actually cached
570570
module BarrierGuard<guardChecksSig/3 guardChecks> {
571-
private predicate guardChecksAdjTypes(Guards::Guards_v3::Guard g, Expr e, boolean branch) {
572-
guardChecks(g, e, branch)
571+
private predicate guardChecksAdjTypes(
572+
Guards::Guards_v3::Guard g, Expr e, Guards::GuardValue gv
573+
) {
574+
guardChecks(g, e, gv)
573575
}
574576

575577
private predicate guardChecksWithWrappers(

java/ql/test/library-tests/dataflow/ssa/A.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,13 @@ void sink(Object o) { }
44

55
boolean isSafe(Object o) { return o == null; }
66

7-
void foo() {
7+
void assertSafe(Object o) { if (o != null) throw new RuntimeException(); }
8+
9+
private boolean wrapIsSafe(Object o) { return isSafe(o); }
10+
11+
private void wrapAssertSafe(Object o) { assertSafe(o); }
12+
13+
void test1() {
814
Object x = source();
915
if (!isSafe(x)) {
1016
x = null;
@@ -21,4 +27,23 @@ void foo() {
2127
}
2228
sink(x);
2329
}
30+
31+
void test2() {
32+
Object x = source();
33+
assertSafe(x);
34+
sink(x);
35+
}
36+
37+
void test3() {
38+
Object x = source();
39+
if (wrapIsSafe(x)) {
40+
sink(x);
41+
}
42+
}
43+
44+
void test4() {
45+
Object x = source();
46+
wrapAssertSafe(x);
47+
sink(x);
48+
}
2449
}

java/ql/test/library-tests/dataflow/ssa/test.ql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@ private predicate isSafe(Guard g, Expr checked, boolean branch) {
1010
)
1111
}
1212

13+
private predicate assertSafe(Guard g, Expr checked, GuardValue gv) {
14+
exists(MethodCall mc | g = mc |
15+
mc.getMethod().hasName("assertSafe") and
16+
checked = mc.getAnArgument() and
17+
gv.getDualValue().isThrowsException()
18+
)
19+
}
20+
1321
module TestConfig implements DataFlow::ConfigSig {
1422
predicate isSource(DataFlow::Node source) {
1523
source.asExpr().(MethodCall).getMethod().hasName("source")
@@ -21,6 +29,8 @@ module TestConfig implements DataFlow::ConfigSig {
2129

2230
predicate isBarrier(DataFlow::Node node) {
2331
node = DataFlow::BarrierGuard<isSafe/3>::getABarrierNode()
32+
or
33+
node = DataFlow::BarrierGuardValue<assertSafe/3>::getABarrierNode()
2434
}
2535
}
2636

shared/controlflow/codeql/controlflow/Guards.qll

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,39 +1280,38 @@ module Make<
12801280
}
12811281
}
12821282

1283-
signature predicate guardChecksSig(Guard g, Expr e, boolean branch);
1283+
signature predicate guardChecksSig(Guard g, Expr e, GuardValue gv);
12841284

12851285
bindingset[this]
1286-
signature class StateSig;
1286+
signature class ParamSig;
12871287

1288-
private module WithState<StateSig State> {
1289-
signature predicate guardChecksSig(Guard g, Expr e, boolean branch, State state);
1288+
private module WithParam<ParamSig P> {
1289+
signature predicate guardChecksSig(Guard g, Expr e, GuardValue gv, P par);
12901290
}
12911291

12921292
/**
12931293
* Extends a `BarrierGuard` input predicate with wrapped invocations.
12941294
*/
12951295
module ValidationWrapper<guardChecksSig/3 guardChecks0> {
1296-
private predicate guardChecksWithState(Guard g, Expr e, boolean branch, Unit state) {
1297-
guardChecks0(g, e, branch) and exists(state)
1296+
private predicate guardChecksWithParam(Guard g, Expr e, GuardValue gv, Unit par) {
1297+
guardChecks0(g, e, gv) and exists(par)
12981298
}
12991299

1300-
private module StatefulWrapper = ValidationWrapperWithState<Unit, guardChecksWithState/4>;
1300+
private module ParameterizedWrapper =
1301+
ParameterizedValidationWrapper<Unit, guardChecksWithParam/4>;
13011302

13021303
/**
13031304
* Holds if the guard `g` validates the SSA definition `def` upon evaluating to `val`.
13041305
*/
13051306
predicate guardChecksDef(Guard g, SsaDefinition def, GuardValue val) {
1306-
StatefulWrapper::guardChecksDef(g, def, val, _)
1307+
ParameterizedWrapper::guardChecksDef(g, def, val, _)
13071308
}
13081309
}
13091310

13101311
/**
13111312
* Extends a `BarrierGuard` input predicate with wrapped invocations.
13121313
*/
1313-
module ValidationWrapperWithState<
1314-
StateSig State, WithState<State>::guardChecksSig/4 guardChecks0>
1315-
{
1314+
module ParameterizedValidationWrapper<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks0> {
13161315
private import WrapperGuard
13171316

13181317
/**
@@ -1321,12 +1320,12 @@ module Make<
13211320
* parameter has been validated by the given guard.
13221321
*/
13231322
private predicate validReturnInValidationWrapper(
1324-
ReturnExpr ret, ParameterPosition ppos, GuardValue retval, State state
1323+
ReturnExpr ret, ParameterPosition ppos, GuardValue retval, P par
13251324
) {
13261325
exists(NonOverridableMethod m, SsaParameterInit param, Guard guard, GuardValue val |
13271326
m.getAReturnExpr() = ret and
13281327
param.getParameter() = m.getParameter(ppos) and
1329-
guardChecksDef(guard, param, val, state)
1328+
guardChecksDef(guard, param, val, par)
13301329
|
13311330
guard.valueControls(ret.getBasicBlock(), val) and
13321331
relevantReturnExprValue(m, ret, retval)
@@ -1341,7 +1340,7 @@ module Make<
13411340
* that the argument has been validated by the given guard.
13421341
*/
13431342
private NonOverridableMethod validationWrapper(
1344-
ParameterPosition ppos, GuardValue retval, State state
1343+
ParameterPosition ppos, GuardValue retval, P par
13451344
) {
13461345
forex(ReturnExpr ret |
13471346
result.getAReturnExpr() = ret and
@@ -1350,12 +1349,12 @@ module Make<
13501349
disjointValues(notRetval, retval)
13511350
)
13521351
|
1353-
validReturnInValidationWrapper(ret, ppos, retval, state)
1352+
validReturnInValidationWrapper(ret, ppos, retval, par)
13541353
)
13551354
or
13561355
exists(SsaParameterInit param, BasicBlock bb, Guard guard, GuardValue val |
13571356
param.getParameter() = result.getParameter(ppos) and
1358-
guardChecksDef(guard, param, val, state) and
1357+
guardChecksDef(guard, param, val, par) and
13591358
guard.valueControls(bb, val) and
13601359
normalExitBlock(bb) and
13611360
retval = TException(false)
@@ -1365,12 +1364,12 @@ module Make<
13651364
/**
13661365
* Holds if the guard `g` validates the expression `e` upon evaluating to `val`.
13671366
*/
1368-
private predicate guardChecks(Guard g, Expr e, GuardValue val, State state) {
1369-
guardChecks0(g, e, val.asBooleanValue(), state)
1367+
private predicate guardChecks(Guard g, Expr e, GuardValue val, P par) {
1368+
guardChecks0(g, e, val, par)
13701369
or
13711370
exists(NonOverridableMethodCall call, ParameterPosition ppos, ArgumentPosition apos |
13721371
g = call and
1373-
call.getMethod() = validationWrapper(ppos, val, state) and
1372+
call.getMethod() = validationWrapper(ppos, val, par) and
13741373
call.getArgument(apos) = e and
13751374
parameterMatch(pragma[only_bind_out](ppos), pragma[only_bind_out](apos))
13761375
)
@@ -1379,9 +1378,9 @@ module Make<
13791378
/**
13801379
* Holds if the guard `g` validates the SSA definition `def` upon evaluating to `val`.
13811380
*/
1382-
predicate guardChecksDef(Guard g, SsaDefinition def, GuardValue val, State state) {
1381+
predicate guardChecksDef(Guard g, SsaDefinition def, GuardValue val, P par) {
13831382
exists(Expr e |
1384-
guardChecks(g, e, val, state) and
1383+
guardChecks(g, e, val, par) and
13851384
guardReadsSsaVar(e, def)
13861385
)
13871386
}

0 commit comments

Comments
 (0)