Skip to content

Commit 1fe1703

Browse files
committed
Java: Add support for boolean MaD barrier guards.
1 parent b29fdd2 commit 1fe1703

File tree

6 files changed

+240
-6
lines changed

6 files changed

+240
-6
lines changed

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

Lines changed: 72 additions & 1 deletion
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,6 +629,46 @@ private module Cached {
601629
)
602630
}
603631

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()
655+
// }
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+
604672
/**
605673
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
606674
* model.
@@ -610,6 +678,9 @@ private module Cached {
610678
exists(SourceSinkInterpretationInput::InterpretNode n |
611679
isBarrierNode(n, kind, model) and n.asNode() = node
612680
)
681+
or
682+
ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
683+
model)) = node
613684
}
614685
}
615686

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

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

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,35 @@ module Make<
215215
]
216216
}
217217

218+
class AcceptingValue extends string {
219+
AcceptingValue() {
220+
this =
221+
[
222+
"true",
223+
"false",
224+
"no-exception",
225+
"zero",
226+
"not-zero",
227+
"null",
228+
"not-null",
229+
]
230+
}
231+
232+
predicate isTrue() { this = "true" }
233+
234+
predicate isFalse() { this = "false" }
235+
236+
predicate isNoException() { this = "no-exception" }
237+
238+
predicate isZero() { this = "zero" }
239+
240+
predicate isNotZero() { this = "not-zero" }
241+
242+
predicate isNull() { this = "null" }
243+
244+
predicate isNotNull() { this = "not-null" }
245+
}
246+
218247
/**
219248
* A class used to represent provenance values for MaD models.
220249
*
@@ -2015,6 +2044,12 @@ module Make<
20152044
not exists(interpretComponent(c))
20162045
}
20172046

2047+
/** Holds if `acceptingvalue` is not a valid barrier guard accepting-value. */
2048+
bindingset[acceptingvalue]
2049+
predicate invalidAcceptingValue(string acceptingvalue) {
2050+
not acceptingvalue instanceof AcceptingValue
2051+
}
2052+
20182053
/** Holds if `provenance` is not a valid provenance value. */
20192054
bindingset[provenance]
20202055
predicate invalidProvenance(string provenance) { not provenance instanceof Provenance }
@@ -2060,6 +2095,15 @@ module Make<
20602095
Element n, string output, string kind, Provenance provenance, string model
20612096
);
20622097

2098+
/**
2099+
* Holds if an external barrier guard specification exists for `n` with input
2100+
* specification `input`, accepting value `acceptingvalue`, and kind `kind`.
2101+
*/
2102+
predicate barrierGuardElement(
2103+
Element n, string input, AcceptingValue acceptingvalue, string kind,
2104+
Provenance provenance, string model
2105+
);
2106+
20632107
class SourceOrSinkElement extends Element;
20642108

20652109
/** An entity used to interpret a source/sink specification. */
@@ -2114,7 +2158,8 @@ module Make<
21142158
private predicate sourceSinkSpec(string spec) {
21152159
sourceElement(_, spec, _, _, _) or
21162160
sinkElement(_, spec, _, _, _) or
2117-
barrierElement(_, spec, _, _, _)
2161+
barrierElement(_, spec, _, _, _) or
2162+
barrierGuardElement(_, spec, _, _, _, _)
21182163
}
21192164

21202165
private module AccessPath = AccessPathSyntax::AccessPath<sourceSinkSpec/1>;
@@ -2180,6 +2225,18 @@ module Make<
21802225
)
21812226
}
21822227

2228+
private predicate barrierGuardElementRef(
2229+
InterpretNode ref, SourceSinkAccessPath input, AcceptingValue acceptingvalue, string kind,
2230+
string model
2231+
) {
2232+
exists(SourceOrSinkElement e |
2233+
barrierGuardElement(e, input, acceptingvalue, kind, _, model) and
2234+
if inputNeedsReferenceExt(input.getToken(0))
2235+
then e = ref.getCallTarget()
2236+
else e = ref.asElement()
2237+
)
2238+
}
2239+
21832240
/** Holds if the first `n` tokens of `output` resolve to the given interpretation. */
21842241
private predicate interpretOutput(
21852242
SourceSinkAccessPath output, int n, InterpretNode ref, InterpretNode node
@@ -2240,7 +2297,7 @@ module Make<
22402297
private predicate interpretInput(
22412298
SourceSinkAccessPath input, int n, InterpretNode ref, InterpretNode node
22422299
) {
2243-
sinkElementRef(ref, input, _, _) and
2300+
(sinkElementRef(ref, input, _, _) or barrierGuardElementRef(ref, input, _, _, _)) and
22442301
n = 0 and
22452302
(
22462303
if input = ""
@@ -2311,6 +2368,19 @@ module Make<
23112368
)
23122369
}
23132370

2371+
/**
2372+
* Holds if `node` is specified as a barrier guard argument with the
2373+
* given kind in a MaD flow model.
2374+
*/
2375+
predicate isBarrierGuardNode(
2376+
InterpretNode node, AcceptingValue acceptingvalue, string kind, string model
2377+
) {
2378+
exists(InterpretNode ref, SourceSinkAccessPath input |
2379+
barrierGuardElementRef(ref, input, acceptingvalue, kind, model) and
2380+
interpretInput(input, input.getNumToken(), ref, node)
2381+
)
2382+
}
2383+
23142384
final private class SourceOrSinkElementFinal = SourceOrSinkElement;
23152385

23162386
signature predicate sourceOrSinkElementSig(

0 commit comments

Comments
 (0)