Java/Dataflow: Propagate MaD-id/model-id to PathGraph.

This commit is contained in:
Anders Schack-Mulligen
2024-01-10 14:40:07 +01:00
parent 1015ee9872
commit 2925e45434
31 changed files with 682 additions and 425 deletions

View File

@@ -15,7 +15,8 @@ private newtype TSinkModel =
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance
) {
ExternalFlow::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)
ExternalFlow::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance,
_)
}
class SinkModel extends TSinkModel {

View File

@@ -259,7 +259,7 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
|
sinkSpec(e, package, type, subtypes, name, signature, ext, input) and
ExternalFlow::sinkModel(package, type, subtypes, name, [signature, ""], ext, input, kind,
provenance)
provenance, _)
)
or
isCustomSink(e, kind) and provenance = "custom-sink"
@@ -272,7 +272,7 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
|
sourceSpec(e, package, type, subtypes, name, signature, ext, output) and
ExternalFlow::sourceModel(package, type, subtypes, name, [signature, ""], ext, output, kind,
provenance)
provenance, _)
)
}

View File

@@ -215,7 +215,7 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
|
sinkSpec(e, package, type, subtypes, name, signature, ext, input) and
ExternalFlow::sinkModel(package, type, subtypes, name, [signature, ""], ext, input, kind,
provenance)
provenance, _)
)
}
@@ -226,7 +226,7 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
|
sourceSpec(e, package, type, subtypes, name, signature, ext, output) and
ExternalFlow::sourceModel(package, type, subtypes, name, [signature, ""], ext, output, kind,
provenance)
provenance, _)
)
}

View File

@@ -113,10 +113,10 @@ abstract class ActiveExperimentalModels extends string {
*/
predicate sourceModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
Extensions::experimentalSourceModel(package, type, subtypes, name, signature, ext, output, kind,
provenance, this)
provenance, this, madId)
}
/**
@@ -124,10 +124,10 @@ abstract class ActiveExperimentalModels extends string {
*/
predicate sinkModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
Extensions::experimentalSinkModel(package, type, subtypes, name, signature, ext, output, kind,
provenance, this)
provenance, this, madId)
}
/**
@@ -135,54 +135,63 @@ abstract class ActiveExperimentalModels extends string {
*/
predicate summaryModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance
string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
Extensions::experimentalSummaryModel(package, type, subtypes, name, signature, ext, input,
output, kind, provenance, this)
output, kind, provenance, this, madId)
}
}
/** Holds if a source model exists for the given parameters. */
predicate sourceModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
Extensions::sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance)
or
any(ActiveExperimentalModels q)
.sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance)
(
Extensions::sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance,
madId)
or
any(ActiveExperimentalModels q)
.sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance, madId)
)
}
/** Holds if a sink model exists for the given parameters. */
predicate sinkModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
Extensions::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)
or
any(ActiveExperimentalModels q)
.sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance)
(
Extensions::sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance,
madId)
or
any(ActiveExperimentalModels q)
.sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, madId)
)
}
/** Holds if a summary model exists for the given parameters. */
predicate summaryModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance
string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
) {
Extensions::summaryModel(package, type, subtypes, name, signature, ext, input, output, kind,
provenance)
or
any(ActiveExperimentalModels q)
.summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance)
(
Extensions::summaryModel(package, type, subtypes, name, signature, ext, input, output, kind,
provenance, madId)
or
any(ActiveExperimentalModels q)
.summaryModel(package, type, subtypes, name, signature, ext, input, output, kind,
provenance, madId)
)
}
/** Holds if a neutral model exists for the given parameters. */
predicate neutralModel = Extensions::neutralModel/6;
private predicate relevantPackage(string package) {
sourceModel(package, _, _, _, _, _, _, _, _) or
sinkModel(package, _, _, _, _, _, _, _, _) or
summaryModel(package, _, _, _, _, _, _, _, _, _)
sourceModel(package, _, _, _, _, _, _, _, _, _) or
sinkModel(package, _, _, _, _, _, _, _, _, _) or
summaryModel(package, _, _, _, _, _, _, _, _, _, _)
}
private predicate packageLink(string shortpkg, string longpkg) {
@@ -212,7 +221,7 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string output, string provenance |
canonicalPkgLink(package, subpkg) and
sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, provenance)
sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, provenance, _)
)
or
part = "sink" and
@@ -220,7 +229,7 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string input, string provenance |
canonicalPkgLink(package, subpkg) and
sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, provenance)
sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, provenance, _)
)
or
part = "summary" and
@@ -228,7 +237,8 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
string ext, string input, string output, string provenance |
canonicalPkgLink(package, subpkg) and
summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, provenance)
summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, provenance,
_)
)
)
}
@@ -238,10 +248,10 @@ module ModelValidation {
private import codeql.dataflow.internal.AccessPathSyntax as AccessPathSyntax
private predicate getRelevantAccessPath(string path) {
summaryModel(_, _, _, _, _, _, path, _, _, _) or
summaryModel(_, _, _, _, _, _, _, path, _, _) or
sinkModel(_, _, _, _, _, _, path, _, _) or
sourceModel(_, _, _, _, _, _, path, _, _)
summaryModel(_, _, _, _, _, _, path, _, _, _, _) or
summaryModel(_, _, _, _, _, _, _, path, _, _, _) or
sinkModel(_, _, _, _, _, _, path, _, _, _) or
sourceModel(_, _, _, _, _, _, path, _, _, _)
}
private module MkAccessPath = AccessPathSyntax::AccessPath<getRelevantAccessPath/1>;
@@ -252,9 +262,9 @@ module ModelValidation {
private string getInvalidModelInput() {
exists(string pred, AccessPath input, AccessPathToken part |
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
sinkModel(_, _, _, _, _, _, input, _, _, _) and pred = "sink"
or
summaryModel(_, _, _, _, _, _, input, _, _, _) and pred = "summary"
summaryModel(_, _, _, _, _, _, input, _, _, _, _) and pred = "summary"
|
(
invalidSpecComponent(input, part) and
@@ -274,9 +284,9 @@ module ModelValidation {
private string getInvalidModelOutput() {
exists(string pred, AccessPath output, AccessPathToken part |
sourceModel(_, _, _, _, _, _, output, _, _) and pred = "source"
sourceModel(_, _, _, _, _, _, output, _, _, _) and pred = "source"
or
summaryModel(_, _, _, _, _, _, _, output, _, _) and pred = "summary"
summaryModel(_, _, _, _, _, _, _, output, _, _, _) and pred = "summary"
|
(
invalidSpecComponent(output, part) and
@@ -291,11 +301,11 @@ module ModelValidation {
}
private module KindValConfig implements SharedModelVal::KindValidationConfigSig {
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _) }
predicate summaryKind(string kind) { summaryModel(_, _, _, _, _, _, _, _, kind, _, _) }
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _) }
predicate sinkKind(string kind) { sinkModel(_, _, _, _, _, _, _, kind, _, _) }
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _) }
predicate sourceKind(string kind) { sourceModel(_, _, _, _, _, _, _, kind, _, _) }
predicate neutralKind(string kind) { neutralModel(_, _, _, _, kind, _) }
}
@@ -307,11 +317,11 @@ module ModelValidation {
string pred, string package, string type, string name, string signature, string ext,
string provenance
|
sourceModel(package, type, _, name, signature, ext, _, _, provenance) and pred = "source"
sourceModel(package, type, _, name, signature, ext, _, _, provenance, _) and pred = "source"
or
sinkModel(package, type, _, name, signature, ext, _, _, provenance) and pred = "sink"
sinkModel(package, type, _, name, signature, ext, _, _, provenance, _) and pred = "sink"
or
summaryModel(package, type, _, name, signature, ext, _, _, _, provenance) and
summaryModel(package, type, _, name, signature, ext, _, _, _, provenance, _) and
pred = "summary"
or
neutralModel(package, type, name, signature, _, provenance) and
@@ -352,11 +362,11 @@ pragma[nomagic]
private predicate elementSpec(
string package, string type, boolean subtypes, string name, string signature, string ext
) {
sourceModel(package, type, subtypes, name, signature, ext, _, _, _)
sourceModel(package, type, subtypes, name, signature, ext, _, _, _, _)
or
sinkModel(package, type, subtypes, name, signature, ext, _, _, _)
sinkModel(package, type, subtypes, name, signature, ext, _, _, _, _)
or
summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _)
summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _, _)
or
neutralModel(package, type, name, signature, _, _) and ext = "" and subtypes = false
}
@@ -494,9 +504,9 @@ private module Cached {
* model.
*/
cached
predicate sourceNode(Node node, string kind) {
predicate sourceNode(Node node, string kind, string model) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSourceNode(n, kind) and n.asNode() = node
isSourceNode(n, kind, model) and n.asNode() = node
)
}
@@ -505,29 +515,45 @@ private module Cached {
* model.
*/
cached
predicate sinkNode(Node node, string kind) {
predicate sinkNode(Node node, string kind, string model) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSinkNode(n, kind) and n.asNode() = node
isSinkNode(n, kind, model) and n.asNode() = node
)
}
}
import Cached
/**
* Holds if `node` is specified as a source with the given kind in a MaD flow
* model.
*/
predicate sourceNode(Node node, string kind) { sourceNode(node, kind, _) }
/**
* Holds if `node` is specified as a sink with the given kind in a MaD flow
* model.
*/
predicate sinkNode(Node node, string kind) { sinkNode(node, kind, _) }
// adapter class for converting Mad summaries to `SummarizedCallable`s
private class SummarizedCallableAdapter extends SummarizedCallable {
SummarizedCallableAdapter() { summaryElement(this, _, _, _, _) }
SummarizedCallableAdapter() { summaryElement(this, _, _, _, _, _) }
private predicate relevantSummaryElementManual(string input, string output, string kind) {
private predicate relevantSummaryElementManual(
string input, string output, string kind, string model
) {
exists(Provenance provenance |
summaryElement(this, input, output, kind, provenance) and
summaryElement(this, input, output, kind, provenance, model) and
provenance.isManual()
)
}
private predicate relevantSummaryElementGenerated(string input, string output, string kind) {
private predicate relevantSummaryElementGenerated(
string input, string output, string kind, string model
) {
exists(Provenance provenance |
summaryElement(this, input, output, kind, provenance) and
summaryElement(this, input, output, kind, provenance, model) and
provenance.isGenerated()
) and
not exists(Provenance provenance |
@@ -536,19 +562,21 @@ private class SummarizedCallableAdapter extends SummarizedCallable {
)
}
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
) {
exists(string kind |
this.relevantSummaryElementManual(input, output, kind)
this.relevantSummaryElementManual(input, output, kind, model)
or
not this.relevantSummaryElementManual(_, _, _) and
this.relevantSummaryElementGenerated(input, output, kind)
not this.relevantSummaryElementManual(_, _, _, _) and
this.relevantSummaryElementGenerated(input, output, kind, model)
|
if kind = "value" then preservesValue = true else preservesValue = false
)
}
override predicate hasProvenance(Provenance provenance) {
summaryElement(this, _, _, _, provenance)
summaryElement(this, _, _, _, provenance, _)
}
}

View File

@@ -126,8 +126,14 @@ class SummarizedCallable = Impl::Public::SummarizedCallable;
* to `SummarizedCallable`.
*/
private class SummarizedSyntheticCallableAdapter extends SummarizedCallable, TSyntheticCallable {
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
this.asSyntheticCallable().propagatesFlow(input, output, preservesValue)
override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
) {
exists(SyntheticCallable sc |
sc = this.asSyntheticCallable() and
sc.propagatesFlow(input, output, preservesValue) and
model = sc
)
}
}

View File

@@ -263,9 +263,10 @@ deprecated private module Config implements FullStateConfigSig {
predicate isBarrierOut(Node node, FlowState state) { none() }
predicate isAdditionalFlowStep(Node node1, Node node2) {
predicate isAdditionalFlowStep(Node node1, Node node2, string model) {
singleConfiguration() and
any(Configuration config).isAdditionalFlowStep(node1, node2)
any(Configuration config).isAdditionalFlowStep(node1, node2) and
model = ""
}
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {

View File

@@ -7,6 +7,7 @@ private import semmle.code.java.dataflow.SSA
private import ContainerFlow
private import semmle.code.java.dataflow.FlowSteps
private import semmle.code.java.dataflow.FlowSummary
private import semmle.code.java.dataflow.ExternalFlow
private import FlowSummaryImpl as FlowSummaryImpl
private import DataFlowNodes
private import codeql.dataflow.VariableCapture as VariableCapture
@@ -576,6 +577,10 @@ predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
/** Extra data-flow steps needed for lambda flow analysis. */
predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preservesValue) { none() }
predicate knownSourceModel(Node source, string model) { sourceNode(source, _, model) }
predicate knownSinkModel(Node sink, string model) { sinkNode(sink, _, model) }
/**
* Holds if flow is allowed to pass from parameter `p` and back to itself as a
* side-effect, resulting in a summary from `p` to itself.

View File

@@ -106,7 +106,7 @@ private module Cached {
*/
cached
predicate localFlowStep(Node node1, Node node2) {
simpleLocalFlowStep0(node1, node2)
simpleLocalFlowStep0(node1, node2, _)
or
adjacentUseUse(node1.asExpr(), node2.asExpr())
or
@@ -122,12 +122,13 @@ private module Cached {
* data flow. It may have less flow than the `localFlowStep` predicate.
*/
cached
predicate simpleLocalFlowStep(Node node1, Node node2) {
simpleLocalFlowStep0(node1, node2)
predicate simpleLocalFlowStep(Node node1, Node node2, string model) {
simpleLocalFlowStep0(node1, node2, model)
or
any(AdditionalValueStep a).step(node1, node2) and
pragma[only_bind_out](node1.getEnclosingCallable()) =
pragma[only_bind_out](node2.getEnclosingCallable()) and
model = "AdditionalValueStep" and
// prevent recursive call
(any(AdditionalValueStep a).step(_, _) implies any())
}
@@ -162,7 +163,7 @@ predicate localMustFlowStep(Node node1, Node node2) {
node1 =
unique(FlowSummaryNode n1 |
FlowSummaryImpl::Private::Steps::summaryLocalStep(n1.getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode(), true)
node2.(FlowSummaryNode).getSummaryNode(), true, _)
)
}
@@ -210,51 +211,55 @@ predicate simpleAstFlowStep(Expr e1, Expr e2) {
exists(InstanceOfExpr ioe | e1 = ioe.getExpr() and e2 = ioe.getPattern().asRecordPattern())
}
private predicate simpleLocalFlowStep0(Node node1, Node node2) {
TaintTrackingUtil::forceCachingInSameStage() and
// Variable flow steps through adjacent def-use and use-use pairs.
exists(SsaExplicitUpdate upd |
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or
upd.getDefiningExpr().(AssignOp) = node1.asExpr() or
upd.getDefiningExpr().(RecordBindingVariableExpr) = node1.asExpr()
|
node2.asExpr() = upd.getAFirstUse() and
private predicate simpleLocalFlowStep0(Node node1, Node node2, string model) {
(
TaintTrackingUtil::forceCachingInSameStage() and
// Variable flow steps through adjacent def-use and use-use pairs.
exists(SsaExplicitUpdate upd |
upd.getDefiningExpr().(VariableAssign).getSource() = node1.asExpr() or
upd.getDefiningExpr().(AssignOp) = node1.asExpr() or
upd.getDefiningExpr().(RecordBindingVariableExpr) = node1.asExpr()
|
node2.asExpr() = upd.getAFirstUse() and
not capturedVariableRead(node2)
)
or
exists(SsaImplicitInit init |
init.isParameterDefinition(node1.asParameter()) and
node2.asExpr() = init.getAFirstUse() and
not capturedVariableRead(node2)
)
or
adjacentUseUse(node1.asExpr(), node2.asExpr()) and
not exists(FieldRead fr |
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _) and
not capturedVariableRead(node2)
)
or
exists(SsaImplicitInit init |
init.isParameterDefinition(node1.asParameter()) and
node2.asExpr() = init.getAFirstUse() and
or
ThisFlow::adjacentThisRefs(node1, node2)
or
adjacentUseUse(node1.(PostUpdateNode).getPreUpdateNode().asExpr(), node2.asExpr()) and
not capturedVariableRead(node2)
)
or
adjacentUseUse(node1.asExpr(), node2.asExpr()) and
not exists(FieldRead fr |
hasNonlocalValue(fr) and fr.getField().isStatic() and fr = node1.asExpr()
or
ThisFlow::adjacentThisRefs(node1.(PostUpdateNode).getPreUpdateNode(), node2)
or
simpleAstFlowStep(node1.asExpr(), node2.asExpr())
or
captureValueStep(node1, node2)
) and
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(node1, _) and
not capturedVariableRead(node2)
or
ThisFlow::adjacentThisRefs(node1, node2)
or
adjacentUseUse(node1.(PostUpdateNode).getPreUpdateNode().asExpr(), node2.asExpr()) and
not capturedVariableRead(node2)
or
ThisFlow::adjacentThisRefs(node1.(PostUpdateNode).getPreUpdateNode(), node2)
or
simpleAstFlowStep(node1.asExpr(), node2.asExpr())
model = ""
or
exists(MethodCall ma, ValuePreservingMethod m, int argNo |
ma.getCallee().getSourceDeclaration() = m and m.returnsValue(argNo)
|
node2.asExpr() = ma and
node1.(ArgumentNode).argumentOf(any(DataFlowCall c | c.asCall() = ma), argNo)
node1.(ArgumentNode).argumentOf(any(DataFlowCall c | c.asCall() = ma), argNo) and
model = "ValuePreservingMethod"
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(node1.(FlowSummaryNode).getSummaryNode(),
node2.(FlowSummaryNode).getSummaryNode(), true)
or
captureValueStep(node1, node2)
node2.(FlowSummaryNode).getSummaryNode(), true, model)
}
/**

View File

@@ -7,7 +7,7 @@
*/
extensible predicate sourceModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance
string output, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
@@ -15,7 +15,7 @@ extensible predicate sourceModel(
*/
extensible predicate sinkModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance
string input, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
@@ -23,7 +23,7 @@ extensible predicate sinkModel(
*/
extensible predicate summaryModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance
string input, string output, string kind, string provenance, QlBuiltins::ExtensionId madId
);
/**
@@ -39,7 +39,7 @@ extensible predicate neutralModel(
*/
extensible predicate experimentalSourceModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance, string filter
string output, string kind, string provenance, string filter, QlBuiltins::ExtensionId madId
);
/**
@@ -48,7 +48,7 @@ extensible predicate experimentalSourceModel(
*/
extensible predicate experimentalSinkModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance, string filter
string input, string kind, string provenance, string filter, QlBuiltins::ExtensionId madId
);
/**
@@ -57,5 +57,6 @@ extensible predicate experimentalSinkModel(
*/
extensible predicate experimentalSummaryModel(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance, string filter
string input, string output, string kind, string provenance, string filter,
QlBuiltins::ExtensionId madId
);

View File

@@ -126,10 +126,10 @@ private predicate relatedArgSpec(Callable c, string spec) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _) or
summaryModel(namespace, type, subtypes, name, signature, ext, _, spec, _, _) or
sourceModel(namespace, type, subtypes, name, signature, ext, spec, _, _) or
sinkModel(namespace, type, subtypes, name, signature, ext, spec, _, _)
summaryModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _, _) or
summaryModel(namespace, type, subtypes, name, signature, ext, _, spec, _, _, _) or
sourceModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _) or
sinkModel(namespace, type, subtypes, name, signature, ext, spec, _, _, _)
|
c = interpretElement(namespace, type, subtypes, name, signature, ext)
)
@@ -192,12 +192,16 @@ module SourceSinkInterpretationInput implements
class Element = J::Element;
predicate sourceElement(Element e, string output, string kind, Public::Provenance provenance) {
predicate sourceElement(
Element e, string output, string kind, Public::Provenance provenance, string model
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
SourceOrSinkElement baseSource, string originalOutput
SourceOrSinkElement baseSource, string originalOutput, QlBuiltins::ExtensionId madId
|
sourceModel(namespace, type, subtypes, name, signature, ext, originalOutput, kind, provenance) and
sourceModel(namespace, type, subtypes, name, signature, ext, originalOutput, kind, provenance,
madId) and
model = "MaD:" + madId.toString() and
baseSource = interpretElement(namespace, type, subtypes, name, signature, ext) and
(
e = baseSource and output = originalOutput
@@ -207,12 +211,16 @@ module SourceSinkInterpretationInput implements
)
}
predicate sinkElement(Element e, string input, string kind, Public::Provenance provenance) {
predicate sinkElement(
Element e, string input, string kind, Public::Provenance provenance, string model
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
SourceOrSinkElement baseSink, string originalInput
SourceOrSinkElement baseSink, string originalInput, QlBuiltins::ExtensionId madId
|
sinkModel(namespace, type, subtypes, name, signature, ext, originalInput, kind, provenance) and
sinkModel(namespace, type, subtypes, name, signature, ext, originalInput, kind, provenance,
madId) and
model = "MaD:" + madId.toString() and
baseSink = interpretElement(namespace, type, subtypes, name, signature, ext) and
(
e = baseSink and originalInput = input
@@ -301,14 +309,17 @@ module Private {
* `input`, output specification `output`, kind `kind`, and provenance `provenance`.
*/
predicate summaryElement(
Input::SummarizedCallableBase c, string input, string output, string kind, string provenance
Input::SummarizedCallableBase c, string input, string output, string kind, string provenance,
string model
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string originalInput, string originalOutput, Callable baseCallable
string originalInput, string originalOutput, Callable baseCallable,
QlBuiltins::ExtensionId madId
|
summaryModel(namespace, type, subtypes, name, signature, ext, originalInput, originalOutput,
kind, provenance) and
kind, provenance, madId) and
model = "MaD:" + madId.toString() and
baseCallable = interpretElement(namespace, type, subtypes, name, signature, ext) and
(
c.asCallable() = baseCallable and input = originalInput and output = originalOutput

View File

@@ -98,7 +98,7 @@ private module Cached {
predicate localTaintStep(DataFlow::Node src, DataFlow::Node sink) {
DataFlow::localFlowStep(src, sink)
or
localAdditionalTaintStep(src, sink)
localAdditionalTaintStep(src, sink, _)
or
// Simple flow through library code is included in the exposed local
// step relation, even though flow is technically inter-procedural
@@ -119,14 +119,15 @@ private module Cached {
* different objects.
*/
cached
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr())
predicate localAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, string model) {
localAdditionalTaintExprStep(src.asExpr(), sink.asExpr(), model)
or
localAdditionalTaintUpdateStep(src.asExpr(),
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr())
sink.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr(), model)
or
exists(DataFlow::Content f |
readStep(src, f, sink) and
model = "" and
not sink.getTypeBound() instanceof PrimitiveType and
not sink.getTypeBound() instanceof BoxedType and
not sink.getTypeBound() instanceof NumberType and
@@ -138,7 +139,7 @@ private module Cached {
)
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(src.(DataFlowPrivate::FlowSummaryNode)
.getSummaryNode(), sink.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false)
.getSummaryNode(), sink.(DataFlowPrivate::FlowSummaryNode).getSummaryNode(), false, model)
}
/**
@@ -146,10 +147,12 @@ private module Cached {
* global taint flow configurations.
*/
cached
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink) {
localAdditionalTaintStep(src, sink) or
entrypointFieldStep(src, sink) or
any(AdditionalTaintStep a).step(src, sink)
predicate defaultAdditionalTaintStep(DataFlow::Node src, DataFlow::Node sink, string model) {
localAdditionalTaintStep(src, sink, model)
or
entrypointFieldStep(src, sink) and model = "entrypointFieldStep"
or
any(AdditionalTaintStep a).step(src, sink) and model = "AdditionalTaintStep"
}
/**
@@ -198,26 +201,29 @@ predicate defaultImplicitTaintRead(DataFlow::Node node, DataFlow::ContentSet c)
* local data flow steps. That is, `src` and `sink` are likely to represent
* different objects.
*/
private predicate localAdditionalTaintExprStep(Expr src, Expr sink) {
sink.(AddExpr).getAnOperand() = src and sink.getType() instanceof TypeString
private predicate localAdditionalTaintExprStep(Expr src, Expr sink, string model) {
(
sink.(AddExpr).getAnOperand() = src and sink.getType() instanceof TypeString
or
sink.(AssignAddExpr).getSource() = src and sink.getType() instanceof TypeString
or
sink.(StringTemplateExpr).getComponent(_) = src
or
sink.(LogicExpr).getAnOperand() = src
) and
model = ""
or
sink.(AssignAddExpr).getSource() = src and sink.getType() instanceof TypeString
constructorStep(src, sink, model)
or
sink.(StringTemplateExpr).getComponent(_) = src
qualifierToMethodStep(src, sink, model)
or
sink.(LogicExpr).getAnOperand() = src
argToMethodStep(src, sink, model)
or
constructorStep(src, sink)
comparisonStep(src, sink) and model = ""
or
qualifierToMethodStep(src, sink)
serializationStep(src, sink) and model = "serializationStep"
or
argToMethodStep(src, sink)
or
comparisonStep(src, sink)
or
serializationStep(src, sink)
or
formatStep(src, sink)
formatStep(src, sink) and model = "formatStep"
}
/**
@@ -226,12 +232,12 @@ private predicate localAdditionalTaintExprStep(Expr src, Expr sink) {
* different objects.
* This is restricted to cases where the step updates the value of `sink`.
*/
private predicate localAdditionalTaintUpdateStep(Expr src, Expr sink) {
qualifierToArgumentStep(src, sink)
private predicate localAdditionalTaintUpdateStep(Expr src, Expr sink, string model) {
qualifierToArgumentStep(src, sink, model)
or
argToArgStep(src, sink)
argToArgStep(src, sink, model)
or
argToQualifierStep(src, sink)
argToQualifierStep(src, sink, model)
}
private class BulkData extends RefType {
@@ -263,19 +269,21 @@ private predicate inputStreamWrapper(Constructor c, int argi) {
}
/** An object construction that preserves the data flow status of any of its arguments. */
private predicate constructorStep(Expr tracked, ConstructorCall sink) {
private predicate constructorStep(Expr tracked, ConstructorCall sink, string model) {
exists(int argi | sink.getArgument(argi) = tracked |
// wrappers constructed by extension
exists(Constructor c, Parameter p, SuperConstructorInvocationStmt sup |
c = sink.getConstructor() and
p = c.getParameter(argi) and
sup.getEnclosingCallable() = c and
constructorStep(p.getAnAccess(), sup)
constructorStep(p.getAnAccess(), sup, model)
)
or
// a custom InputStream that wraps a tainted data source is tainted
model = "inputStreamWrapper" and
inputStreamWrapper(sink.getConstructor(), argi)
or
model = "TaintPreservingCallable" and
sink.getConstructor().(TaintPreservingCallable).returnsTaintFrom(argToParam(sink, argi))
)
}
@@ -289,8 +297,9 @@ private int argToParam(Call call, int argIdx) {
}
/** Access to a method that passes taint from qualifier to argument. */
private predicate qualifierToArgumentStep(Expr tracked, Expr sink) {
private predicate qualifierToArgumentStep(Expr tracked, Expr sink, string model) {
exists(MethodCall ma, int arg |
model = "TaintPreservingCallable" and
ma.getMethod().(TaintPreservingCallable).transfersTaint(-1, argToParam(ma, arg)) and
tracked = ma.getQualifier() and
sink = ma.getArgument(arg)
@@ -298,17 +307,19 @@ private predicate qualifierToArgumentStep(Expr tracked, Expr sink) {
}
/** Access to a method that passes taint from the qualifier. */
private predicate qualifierToMethodStep(Expr tracked, MethodCall sink) {
taintPreservingQualifierToMethod(sink.getMethod()) and
private predicate qualifierToMethodStep(Expr tracked, MethodCall sink, string model) {
taintPreservingQualifierToMethod(sink.getMethod(), model) and
tracked = sink.getQualifier()
}
/**
* Methods that return tainted data when called on tainted data.
*/
private predicate taintPreservingQualifierToMethod(Method m) {
private predicate taintPreservingQualifierToMethod(Method m, string model) {
model = "" and
m instanceof CloneMethod
or
model = "%StringWriter" and
m.getDeclaringType().getQualifiedName().matches("%StringWriter") and
(
m.getName() = "getBuffer"
@@ -316,29 +327,34 @@ private predicate taintPreservingQualifierToMethod(Method m) {
m.getName() = "toString"
)
or
model = "TypeObjectInputStream.read%" and
m.getDeclaringType() instanceof TypeObjectInputStream and
m.getName().matches("read%")
or
model = "SpringUntrustedDataType.getter" and
m instanceof GetterMethod and
m.getDeclaringType().getADescendant() instanceof SpringUntrustedDataType and
not m.getDeclaringType() instanceof TypeObject
or
model = "TaintPreservingCallable" and
m.(TaintPreservingCallable).returnsTaintFrom(-1)
or
model = "JaxRsResourceMethod" and
exists(JaxRsResourceMethod resourceMethod |
m.(GetterMethod).getDeclaringType() = resourceMethod.getAParameter().getType()
)
}
/** Access to a method that passes taint from an argument. */
private predicate argToMethodStep(Expr tracked, MethodCall sink) {
private predicate argToMethodStep(Expr tracked, MethodCall sink, string model) {
exists(Method m, int i |
m = sink.getMethod() and
taintPreservingArgumentToMethod(m, argToParam(sink, i)) and
taintPreservingArgumentToMethod(m, argToParam(sink, i), model) and
tracked = sink.getArgument(i)
)
or
exists(Method springResponseEntityOfOk |
model = "SpringResponseEntity" and
sink.getMethod() = springResponseEntityOfOk and
springResponseEntityOfOk.getDeclaringType() instanceof SpringResponseEntity and
springResponseEntityOfOk.hasName(["ok", "of"]) and
@@ -347,6 +363,7 @@ private predicate argToMethodStep(Expr tracked, MethodCall sink) {
)
or
exists(Method springResponseEntityBody |
model = "SpringResponseEntityBodyBuilder" and
sink.getMethod() = springResponseEntityBody and
springResponseEntityBody.getDeclaringType() instanceof SpringResponseEntityBodyBuilder and
springResponseEntityBody.hasName("body") and
@@ -359,7 +376,8 @@ private predicate argToMethodStep(Expr tracked, MethodCall sink) {
* Holds if `method` is a library method that returns tainted data if its
* `arg`th argument is tainted.
*/
private predicate taintPreservingArgumentToMethod(Method method, int arg) {
private predicate taintPreservingArgumentToMethod(Method method, int arg, string model) {
model = "org.apache.commons.codec.binary.Base64" and
method.getDeclaringType().hasQualifiedName("org.apache.commons.codec.binary", "Base64") and
(
method.getName() = "decodeBase64" and arg = 0
@@ -367,6 +385,7 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
method.getName().matches("encodeBase64%") and arg = 0
)
or
model = "TaintPreservingCallable" and
method.(TaintPreservingCallable).returnsTaintFrom(arg)
}
@@ -374,8 +393,9 @@ private predicate taintPreservingArgumentToMethod(Method method, int arg) {
* Holds if `tracked` and `sink` are arguments to a method that transfers taint
* between arguments.
*/
private predicate argToArgStep(Expr tracked, Expr sink) {
private predicate argToArgStep(Expr tracked, Expr sink, string model) {
exists(MethodCall ma, Method method, int input, int output |
model = "TaintPreservingCallable" and
method.(TaintPreservingCallable).transfersTaint(argToParam(ma, input), argToParam(ma, output)) and
ma.getMethod() = method and
ma.getArgument(input) = tracked and
@@ -387,8 +407,9 @@ private predicate argToArgStep(Expr tracked, Expr sink) {
* Holds if `tracked` is the argument of a method that transfers taint
* from the argument to the qualifier and `sink` is the qualifier.
*/
private predicate argToQualifierStep(Expr tracked, Expr sink) {
private predicate argToQualifierStep(Expr tracked, Expr sink, string model) {
exists(Method m, int i, MethodCall ma |
model = "TaintPreservingCallable" and
taintPreservingArgumentToQualifier(m, argToParam(ma, i)) and
ma.getMethod() = m and
tracked = ma.getArgument(i) and

View File

@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
defaultAdditionalTaintStep(node1, node2, _)
}
/**

View File

@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
defaultAdditionalTaintStep(node1, node2, _)
}
/**

View File

@@ -127,7 +127,7 @@ abstract deprecated class Configuration extends DataFlow::Configuration {
final override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
this.isAdditionalTaintStep(node1, node2) or
defaultAdditionalTaintStep(node1, node2)
defaultAdditionalTaintStep(node1, node2, _)
}
/**

View File

@@ -71,10 +71,13 @@ private class SummarizedCallableWithCallback extends SummarizedCallable {
SummarizedCallableWithCallback() { mayInvokeCallback(this.asCallable(), pos) }
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
) {
input = "Argument[" + pos + "]" and
output = "Argument[" + pos + "].Parameter[-1]" and
preservesValue = true
preservesValue = true and
model = "heuristic-callback"
}
override predicate hasProvenance(Provenance provenance) { provenance = "hq-generated" }

View File

@@ -18,7 +18,7 @@ private class ExploitableStringLiteral extends StringLiteral {
* where -1 is the qualifier; or -2 if no such argument exists.
*/
private predicate regexSinkKindInfo(string kind, boolean full, int strArg) {
sinkModel(_, _, _, _, _, _, _, kind, _) and
sinkModel(_, _, _, _, _, _, _, kind, _, _) and
exists(string fullStr, string strArgStr |
(
full = true and fullStr = "f"

View File

@@ -77,7 +77,7 @@ class ExternalApiDataNode extends DataFlow::Node {
) and
// Not already modeled as a taint step (we need both of these to handle `AdditionalTaintStep` subclasses as well)
not TaintTracking::localTaintStep(this, _) and
not TaintTracking::defaultAdditionalTaintStep(this, _) and
not TaintTracking::defaultAdditionalTaintStep(this, _, _) and
// Not a call to a known safe external API
not call.getCallee() instanceof SafeExternalApiMethod
}

View File

@@ -65,7 +65,7 @@ class ExternalApi extends Callable {
pragma[nomagic]
predicate hasSummary() {
this = any(SummarizedCallable sc).asCallable() or
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _, _)
}
pragma[nomagic]

View File

@@ -27,7 +27,7 @@ predicate summaryModelRow(
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance, string row
) {
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance) and
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance, _) and
row =
package + ";" //
+ type + ";" //
@@ -61,7 +61,7 @@ private class CallableToTest extends Callable {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) and
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _) and
this = interpretElement(namespace, type, subtypes, name, signature, ext) and
this.isPublic() and
getRootType(this.getDeclaringType()).(RefType).isPublic()

View File

@@ -11,7 +11,7 @@ from
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string kind, string provenance
where
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance, _) and
not provenance.matches("%generated")
select package, type, subtypes, name, signature, ext, input, kind, provenance order by
package, type, name, signature, input, kind

View File

@@ -11,7 +11,7 @@ from
string package, string type, boolean subtypes, string name, string signature, string ext,
string output, string kind, string provenance
where
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance) and
sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance, _) and
not provenance.matches("%generated")
select package, type, subtypes, name, signature, ext, output, kind, provenance order by
package, type, name, signature, output, kind

View File

@@ -11,7 +11,7 @@ from
string package, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance
where
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance) and
summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance, _) and
not provenance.matches("%generated")
select package, type, subtypes, name, signature, ext, input, output, kind, provenance order by
package, type, name, signature, input, output, kind

View File

@@ -29,7 +29,7 @@ class ExternalEndpoint extends Endpoint {
override predicate hasSummary() {
Endpoint.super.hasSummary()
or
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _)
TaintTracking::localAdditionalTaintStep(this.getAnInput(), _, _)
}
override predicate isSource() {

View File

@@ -8,7 +8,7 @@ private import ModelEditor
* A class of effectively public callables from source code.
*/
class PublicEndpointFromSource extends Endpoint, ModelApi {
override predicate isSource() { SourceSinkInterpretationInput::sourceElement(this, _, _, _) }
override predicate isSource() { SourceSinkInterpretationInput::sourceElement(this, _, _, _, _) }
override predicate isSink() { SourceSinkInterpretationInput::sinkElement(this, _, _, _) }
override predicate isSink() { SourceSinkInterpretationInput::sinkElement(this, _, _, _, _) }
}

View File

@@ -14,7 +14,7 @@ predicate taintFlowUpdate(DataFlow::ParameterNode p1, DataFlow::ParameterNode p2
predicate summaryStep(FlowSummaryNode src, FlowSummaryNode sink) {
FlowSummaryImpl::Private::Steps::summaryLocalStep(src.getSummaryNode(), sink.getSummaryNode(),
false) or
false, _) or
FlowSummaryImpl::Private::Steps::summaryReadStep(src.getSummaryNode(), _, sink.getSummaryNode()) or
FlowSummaryImpl::Private::Steps::summaryStoreStep(src.getSummaryNode(), _, sink.getSummaryNode())
}
@@ -22,7 +22,7 @@ predicate summaryStep(FlowSummaryNode src, FlowSummaryNode sink) {
from DataFlow::Node src, DataFlow::Node sink
where
(
localAdditionalTaintStep(src, sink) or
localAdditionalTaintStep(src, sink, _) or
FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(src, sink, _)
) and
not summaryStep(src, sink)