Skip to content

Commit 4aa025c

Browse files
committed
Java: Add support for boolean MaD barrier guards.
1 parent 15e467d commit 4aa025c

File tree

6 files changed

+227
-6
lines changed

6 files changed

+227
-6
lines changed

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

Lines changed: 65 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,39 @@ private module Cached {
601629
)
602630
}
603631

632+
private newtype TKindModelPair =
633+
TMkPair(string kind, string model) { isBarrierGuardNode(_, _, kind, model) }
634+
635+
private GuardValue convertAcceptingValue(AcceptingValue av) {
636+
av.isTrue() and result.asBooleanValue() = true
637+
or
638+
av.isFalse() and result.asBooleanValue() = false
639+
or
640+
av.isNoException() and result.getDualValue().isThrowsException()
641+
or
642+
av.isZero() and result.asIntValue() = 0
643+
or
644+
av.isNotZero() and result.getDualValue().asIntValue() = 0
645+
or
646+
av.isNull() and result.isNullValue()
647+
or
648+
av.isNotNull() and result.isNonNullValue()
649+
}
650+
651+
private predicate barrierGuardChecks(Guard g, Expr e, GuardValue gv, TKindModelPair kmp) {
652+
exists(
653+
SourceSinkInterpretationInput::InterpretNode n, AcceptingValue acceptingvalue, string kind,
654+
string model
655+
|
656+
isBarrierGuardNode(n, acceptingvalue, kind, model) and
657+
n.asNode().asExpr() = e and
658+
kmp = TMkPair(kind, model) and
659+
gv = convertAcceptingValue(acceptingvalue)
660+
|
661+
g.(Call).getAnArgument() = e or g.(MethodCall).getQualifier() = e
662+
)
663+
}
664+
604665
/**
605666
* Holds if `node` is specified as a barrier with the given kind in a MaD flow
606667
* model.
@@ -610,6 +671,9 @@ private module Cached {
610671
exists(SourceSinkInterpretationInput::InterpretNode n |
611672
isBarrierNode(n, kind, model) and n.asNode() = node
612673
)
674+
or
675+
ParameterizedBarrierGuard<TKindModelPair, barrierGuardChecks/4>::getABarrierNode(TMkPair(kind,
676+
model)) = node
613677
}
614678
}
615679

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,3 +420,31 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
420420
/** Gets a node that is safely guarded by the given guard check. */
421421
Node getABarrierNode() { result = BarrierGuardValue<guardChecks0/3>::getABarrierNode() }
422422
}
423+
424+
bindingset[this]
425+
private signature class ParamSig;
426+
427+
private module WithParam<ParamSig P> {
428+
/**
429+
* Holds if the guard `g` validates the expression `e` upon evaluating to `gv`.
430+
*
431+
* The expression `e` is expected to be a syntactic part of the guard `g`.
432+
* For example, the guard `g` might be a call `isSafe(x)` and the expression `e`
433+
* the argument `x`.
434+
*/
435+
signature predicate guardChecksSig(Guard g, Expr e, GuardValue gv, P param);
436+
}
437+
438+
/**
439+
* Provides a set of barrier nodes for a guard that validates an expression.
440+
*
441+
* This is expected to be used in `isBarrier`/`isSanitizer` definitions
442+
* in data flow and taint tracking.
443+
*/
444+
module ParameterizedBarrierGuard<ParamSig P, WithParam<P>::guardChecksSig/4 guardChecks> {
445+
/** Gets a node that is safely guarded by the given guard check. */
446+
Node getABarrierNode(P param) {
447+
SsaFlow::asNode(result) =
448+
SsaImpl::DataFlowIntegration::ParameterizedBarrierGuard<P, guardChecks/4>::getABarrierNode(param)
449+
}
450+
}

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: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,36 @@ private module Cached {
588588

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

593623
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)