Skip to content

Commit 6780c9e

Browse files
committed
Java: Add support for boolean MaD barrier guards.
1 parent 8ad72c4 commit 6780c9e

File tree

6 files changed

+238
-19
lines changed

6 files changed

+238
-19
lines changed

java/ql/lib/semmle/code/java/dataflow/ExternalFlow.qll

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ module;
9191

9292
import java
9393
private import semmle.code.java.dataflow.DataFlow::DataFlow
94+
private import semmle.code.java.controlflow.Guards
9495
private import FlowSummary as FlowSummary
9596
private import internal.DataFlowPrivate
9697
private import internal.FlowSummaryImpl
@@ -183,6 +184,15 @@ predicate barrierModel(
183184
madId)
184185
}
185186

187+
/** Holds if a barrier guard model exists for the given parameters. */
188+
predicate barrierGuardModel(
189+
string package, string type, boolean subtypes, string name, string signature, string ext,
190+
string input, string acceptingvalue, string kind, string provenance, QlBuiltins::ExtensionId madId
191+
) {
192+
Extensions::barrierGuardModel(package, type, subtypes, name, signature, ext, input,
193+
acceptingvalue, kind, provenance, madId)
194+
}
195+
186196
/** Holds if a summary model exists for the given parameters. */
187197
predicate summaryModel(
188198
string package, string type, boolean subtypes, string name, string signature, string ext,
@@ -315,7 +325,8 @@ module ModelValidation {
315325
summaryModel(_, _, _, _, _, _, _, path, _, _, _) or
316326
sinkModel(_, _, _, _, _, _, path, _, _, _) or
317327
sourceModel(_, _, _, _, _, _, path, _, _, _) or
318-
barrierModel(_, _, _, _, _, _, path, _, _, _)
328+
barrierModel(_, _, _, _, _, _, path, _, _, _) or
329+
barrierGuardModel(_, _, _, _, _, _, path, _, _, _, _)
319330
}
320331

321332
private module MkAccessPath = AccessPathSyntax::AccessPath<getRelevantAccessPath/1>;
@@ -328,6 +339,8 @@ module ModelValidation {
328339
exists(string pred, AccessPath input, AccessPathToken part |
329340
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
330341
or
342+
barrierGuardModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "barrier guard"
343+
or
331344
summaryModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "summary"
332345
|
333346
(
@@ -373,6 +386,8 @@ module ModelValidation {
373386
sinkModel(_, _, _, _, _, _, _, kind, _, _)
374387
or
375388
barrierModel(_, _, _, _, _, _, _, kind, _, _)
389+
or
390+
barrierGuardModel(_, _, _, _, _, _, _, _, kind, _, _)
376391
}
377392

378393
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _, _) }
@@ -393,6 +408,9 @@ module ModelValidation {
393408
or
394409
barrierModel(package, type, _, name, signature, ext, _, _, provenance, _) and pred = "barrier"
395410
or
411+
barrierGuardModel(package, type, _, name, signature, ext, _, _, _, provenance, _) and
412+
pred = "barrier guard"
413+
or
396414
summaryModel(package, type, _, name, signature, ext, _, _, _, provenance, _) and
397415
pred = "summary"
398416
or
@@ -418,6 +436,14 @@ module ModelValidation {
418436
invalidProvenance(provenance) and
419437
result = "Unrecognized provenance description \"" + provenance + "\" in " + pred + " model."
420438
)
439+
or
440+
exists(string acceptingvalue |
441+
barrierGuardModel(_, _, _, _, _, _, _, acceptingvalue, _, _, _) and
442+
invalidAcceptingValue(acceptingvalue) and
443+
result =
444+
"Unrecognized accepting value description \"" + acceptingvalue +
445+
"\" in barrier guard model."
446+
)
421447
}
422448

423449
/** Holds if some row in a MaD flow model appears to contain typos. */
@@ -440,6 +466,8 @@ private predicate elementSpec(
440466
or
441467
barrierModel(package, type, subtypes, name, signature, ext, _, _, _, _)
442468
or
469+
barrierGuardModel(package, type, subtypes, name, signature, ext, _, _, _, _, _)
470+
or
443471
summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _, _)
444472
or
445473
neutralModel(package, type, name, signature, _, _) and ext = "" and subtypes = true
@@ -601,13 +629,46 @@ private module Cached {
601629
)
602630
}
603631

604-
// private predicate barrierGuardChecks() {
605-
// exists(
606-
// SourceSinkInterpretationInput::InterpretNode n, ArgumentNode arg, GuardAcceptingValue gv
607-
// |
608-
// isBarrierGuardNode(n, gv, kind, model) and n.asNode() = arg
609-
// )
632+
private newtype TKindModelPair =
633+
TMkPair(string kind, string model) { isBarrierGuardNode(_, _, kind, model) }
634+
635+
private boolean convertAcceptingValue(AcceptingValue av) {
636+
av.isTrue() and result = true
637+
or
638+
av.isFalse() and result = false
639+
}
640+
641+
// private GuardValue convertAcceptingValue(AcceptingValue av) {
642+
// av.isTrue() and result.asBooleanValue() = true
643+
// or
644+
// av.isFalse() and result.asBooleanValue() = false
645+
// or
646+
// av.isNoException() and result.getDualValue().isThrowsException()
647+
// or
648+
// av.isZero() and result.asIntValue() = 0
649+
// or
650+
// av.isNotZero() and result.getDualValue().asIntValue() = 0
651+
// or
652+
// av.isNull() and result.isNullValue()
653+
// or
654+
// av.isNotNull() and result.isNonNullValue()
610655
// }
656+
// private predicate barrierGuardChecks(Guard g, Expr e, GuardValue gv, TKindModelPair kmp) {
657+
private predicate barrierGuardChecks(Guard g, Expr e, boolean branch, TKindModelPair kmp) {
658+
exists(
659+
SourceSinkInterpretationInput::InterpretNode n, AcceptingValue acceptingvalue, string kind,
660+
string model
661+
|
662+
isBarrierGuardNode(n, acceptingvalue, kind, model) and
663+
n.asNode().asExpr() = e and
664+
kmp = TMkPair(kind, model) and
665+
// gv = convertAcceptingValue(acceptingvalue)
666+
branch = convertAcceptingValue(acceptingvalue)
667+
|
668+
g.(Call).getAnArgument() = e or g.(MethodCall).getQualifier() = e
669+
)
670+
}
671+
611672
/**
612673
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
613674
* model.
@@ -617,8 +678,9 @@ private module Cached {
617678
exists(SourceSinkInterpretationInput::InterpretNode n |
618679
isBarrierNode(n, kind, model) and n.asNode() = node
619680
)
620-
// or
621-
// BarrierGuard<barrierGuardChecks/3>::getABarrierNode() = node
681+
or
682+
ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
683+
model)) = node
622684
}
623685
}
624686

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,3 +396,32 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
396396
SsaImpl::DataFlowIntegration::BarrierGuard<guardChecks/3>::getABarrierNode()
397397
}
398398
}
399+
400+
bindingset[this]
401+
signature class ParamSig;
402+
403+
module WithParam<ParamSig P> {
404+
/**
405+
* Holds if the guard `g` validates the expression `e` upon evaluating to `gv`.
406+
*
407+
* The expression `e` is expected to be a syntactic part of the guard `g`.
408+
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
409+
* the argument `x`.
410+
*/
411+
// signature predicate guardChecksSig(Guard g, Expr e, GuardValue gv, P param);
412+
signature predicate guardChecksSig(Guard g, Expr e, boolean branch, P param);
413+
}
414+
415+
/**
416+
* Provides a set of barrier nodes for a guard that validates an expression.
417+
*
418+
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
419+
* in data flow and taint tracking.
420+
*/
421+
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
422+
/** Gets a node that is safely guarded by the given guard check. */
423+
Node getABarrierNode(P param) {
424+
SsaFlow::asNode(result) =
425+
SsaImpl::DataFlowIntegration::ParameterizedBarrierGuard<P, guardChecks/4>::getABarrierNode(param)
426+
}
427+
}

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ extensible predicate barrierModel(
2828
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
2929
);
3030

31+
/**
32+
* Holds if a barrier guard model exists for the given parameters.
33+
*/
34+
extensible predicate barrierGuardModel(
35+
string package, string type, boolean subtypes, string name, string signature, string ext,
36+
string input, string acceptingvalue, string kind, string provenance, QlBuiltins::ExtensionId madId
37+
);
38+
3139
/**
3240
* Holds if a summary model exists for the given parameters.
3341
*/

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

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ private predicate relatedArgSpec(Callable c, string spec) {
159159
summaryModel(namespace, type, subtypes, name, signature, ext, _, spec, _, _, _) or
160160
sourceModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _) or
161161
sinkModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _) or
162-
barrierModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _)
162+
barrierModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _) or
163+
barrierGuardModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _, _)
163164
|
164165
c = interpretElement(namespace, type, subtypes, name, signature, ext, _)
165166
)
@@ -267,8 +268,28 @@ module SourceSinkInterpretationInput implements
267268
string namespace, string type, boolean subtypes, string name, string signature, string ext,
268269
SourceOrSinkElement baseBarrier, string originalOutput, QlBuiltins::ExtensionId madId
269270
|
270-
barrierModel(namespace, type, subtypes, name, signature, ext, originalOutput, kind, provenance,
271-
madId) and
271+
barrierModel(namespace, type, subtypes, name, signature, ext, originalOutput, kind,
272+
provenance, madId) and
273+
model = "MaD:" + madId.toString() and
274+
baseBarrier = interpretElement(namespace, type, subtypes, name, signature, ext, _) and
275+
(
276+
e = baseBarrier and output = originalOutput
277+
or
278+
correspondingKotlinParameterDefaultsArgSpec(baseBarrier, e, originalOutput, output)
279+
)
280+
)
281+
}
282+
283+
predicate barrierGuardElement(
284+
Element e, string output, Public::AcceptingValue acceptingvalue, string kind,
285+
Public::Provenance provenance, string model
286+
) {
287+
exists(
288+
string namespace, string type, boolean subtypes, string name, string signature, string ext,
289+
SourceOrSinkElement baseBarrier, string originalOutput, QlBuiltins::ExtensionId madId
290+
|
291+
barrierGuardModel(namespace, type, subtypes, name, signature, ext, originalOutput,
292+
acceptingvalue, kind, provenance, madId) and
272293
model = "MaD:" + madId.toString() and
273294
baseBarrier = interpretElement(namespace, type, subtypes, name, signature, ext, _) and
274295
(

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,41 @@ private module Cached {
586586

587587
predicate getABarrierNode = getABarrierNodeImpl/0;
588588
}
589+
590+
bindingset[this]
591+
signature class ParamSig;
592+
593+
cached // nothing is actually cached
594+
module WithParam<ParamSig P> {
595+
// signature predicate guardChecksSig(Guards::Guard g, Expr e, Guards::GuardValue gv, P param);
596+
signature predicate guardChecksSig(Guards::Guard g, Expr e, boolean branch, P param);
597+
}
598+
599+
cached // nothing is actually cached
600+
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
601+
// private predicate guardChecksAdjTypes(Guards::Guards_v3::Guard g, Expr e, Guards::GuardValue gv, P param) {
602+
// guardChecks(g, e, gv, param)
603+
// }
604+
private predicate guardChecksAdjTypes(
605+
Guards::Guards_v3::Guard g, Expr e, boolean branch, P param
606+
) {
607+
guardChecks(g, e, branch, param)
608+
}
609+
610+
private predicate guardChecksWithWrappers(
611+
DataFlowIntegrationInput::Guard g, Definition def, Guards::GuardValue val, P param
612+
) {
613+
Guards::Guards_v3::ValidationWrapperWithState<P, guardChecksAdjTypes/4>::guardChecksDef(g,
614+
def, val, param)
615+
}
616+
617+
private Node getABarrierNodeImpl(P param) {
618+
result =
619+
DataFlowIntegrationImpl::BarrierGuardDefWithState<P, guardChecksWithWrappers/4>::getABarrierNode(param)
620+
}
621+
622+
predicate getABarrierNode = getABarrierNodeImpl/1;
623+
}
589624
}
590625

591626
cached

0 commit comments

Comments
 (0)