mirror of
https://github.com/github/codeql.git
synced 2026-04-25 00:35:20 +02:00
C#: Add alert provenance plumbing.
This commit is contained in:
@@ -5,6 +5,7 @@ private import DataFlowImplCommon
|
||||
private import ControlFlowReachability
|
||||
private import FlowSummaryImpl as FlowSummaryImpl
|
||||
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
|
||||
private import semmle.code.csharp.dataflow.internal.ExternalFlow
|
||||
private import semmle.code.csharp.Conversion
|
||||
private import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl
|
||||
private import semmle.code.csharp.ExprOrStmtParent
|
||||
@@ -796,7 +797,7 @@ module LocalFlow {
|
||||
node1 =
|
||||
unique(FlowSummaryNode n1 |
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(n1.getSummaryNode(),
|
||||
node2.(FlowSummaryNode).getSummaryNode(), true)
|
||||
node2.(FlowSummaryNode).getSummaryNode(), true, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -809,36 +810,39 @@ predicate localMustFlowStep = LocalFlow::localMustFlowStep/2;
|
||||
* is handled by the global data-flow library, but includes various other steps
|
||||
* that are only relevant for global flow.
|
||||
*/
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
exists(SsaImpl::DefinitionExt def |
|
||||
not LocalFlow::usesInstanceField(def) and
|
||||
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
||||
|
|
||||
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo)
|
||||
predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo, string model) {
|
||||
(
|
||||
LocalFlow::localFlowStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
|
||||
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _) and
|
||||
nodeFrom != nodeTo
|
||||
or
|
||||
// Flow into phi (read)/uncertain SSA definition node from read
|
||||
exists(Node read | LocalFlow::localFlowSsaInputFromRead(read, def, nodeTo) |
|
||||
nodeFrom = read and
|
||||
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
|
||||
exists(SsaImpl::DefinitionExt def |
|
||||
not LocalFlow::usesInstanceField(def) and
|
||||
not def instanceof VariableCapture::CapturedSsaDefinitionExt
|
||||
|
|
||||
LocalFlow::localSsaFlowStep(def, nodeFrom, nodeTo)
|
||||
or
|
||||
nodeFrom.(PostUpdateNode).getPreUpdateNode() = read
|
||||
LocalFlow::localSsaFlowStepUseUse(def, nodeFrom, nodeTo) and
|
||||
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _) and
|
||||
nodeFrom != nodeTo
|
||||
or
|
||||
// Flow into phi (read)/uncertain SSA definition node from read
|
||||
exists(Node read | LocalFlow::localFlowSsaInputFromRead(read, def, nodeTo) |
|
||||
nodeFrom = read and
|
||||
not FlowSummaryImpl::Private::Steps::prohibitsUseUseFlow(nodeFrom, _)
|
||||
or
|
||||
nodeFrom.(PostUpdateNode).getPreUpdateNode() = read
|
||||
)
|
||||
)
|
||||
)
|
||||
or
|
||||
nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode)
|
||||
or
|
||||
VariableCapture::valueStep(nodeFrom, nodeTo)
|
||||
or
|
||||
nodeTo = nodeFrom.(LocalFunctionCreationNode).getAnAccess(true)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), true)
|
||||
or
|
||||
nodeTo.(ObjectCreationNode).getPreUpdateNode() = nodeFrom.(ObjectInitializerNode)
|
||||
or
|
||||
VariableCapture::valueStep(nodeFrom, nodeTo)
|
||||
or
|
||||
nodeTo = nodeFrom.(LocalFunctionCreationNode).getAnAccess(true)
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -902,7 +906,7 @@ private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, bool
|
||||
FlowSummaryImpl::Private::SummarizedCallableImpl sc,
|
||||
FlowSummaryImpl::Private::SummaryComponentStack input
|
||||
|
|
||||
sc.propagatesFlow(input, _, _) and
|
||||
sc.propagatesFlow(input, _, _, _) and
|
||||
input.contains(FlowSummaryImpl::Private::SummaryComponent::content(f.getContent()))
|
||||
)
|
||||
)
|
||||
@@ -2874,6 +2878,10 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
|
||||
preservesValue = true
|
||||
}
|
||||
|
||||
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.
|
||||
|
||||
@@ -97,9 +97,9 @@ private import semmle.code.csharp.commons.QualifiedName
|
||||
private import codeql.mad.ModelValidation as SharedModelVal
|
||||
|
||||
private predicate relevantNamespace(string namespace) {
|
||||
sourceModel(namespace, _, _, _, _, _, _, _, _) or
|
||||
sinkModel(namespace, _, _, _, _, _, _, _, _) or
|
||||
summaryModel(namespace, _, _, _, _, _, _, _, _, _)
|
||||
sourceModel(namespace, _, _, _, _, _, _, _, _, _) or
|
||||
sinkModel(namespace, _, _, _, _, _, _, _, _, _) or
|
||||
summaryModel(namespace, _, _, _, _, _, _, _, _, _, _)
|
||||
}
|
||||
|
||||
private predicate namespaceLink(string shortns, string longns) {
|
||||
@@ -129,7 +129,7 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string output, string provenance |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance)
|
||||
sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance, _)
|
||||
)
|
||||
or
|
||||
part = "sink" and
|
||||
@@ -137,7 +137,7 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input, string provenance |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance)
|
||||
sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance, _)
|
||||
)
|
||||
or
|
||||
part = "summary" and
|
||||
@@ -145,7 +145,7 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
|
||||
strictcount(string subns, string type, boolean subtypes, string name, string signature,
|
||||
string ext, string input, string output, string provenance |
|
||||
canonicalNamespaceLink(namespace, subns) and
|
||||
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance)
|
||||
summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -155,10 +155,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>;
|
||||
@@ -169,9 +169,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
|
||||
@@ -191,9 +191,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
|
||||
@@ -208,11 +208,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, _) }
|
||||
}
|
||||
@@ -224,11 +224,11 @@ module ModelValidation {
|
||||
string pred, string namespace, string type, string name, string signature, string ext,
|
||||
string provenance
|
||||
|
|
||||
sourceModel(namespace, type, _, name, signature, ext, _, _, provenance) and pred = "source"
|
||||
sourceModel(namespace, type, _, name, signature, ext, _, _, provenance, _) and pred = "source"
|
||||
or
|
||||
sinkModel(namespace, type, _, name, signature, ext, _, _, provenance) and pred = "sink"
|
||||
sinkModel(namespace, type, _, name, signature, ext, _, _, provenance, _) and pred = "sink"
|
||||
or
|
||||
summaryModel(namespace, type, _, name, signature, ext, _, _, _, provenance) and
|
||||
summaryModel(namespace, type, _, name, signature, ext, _, _, _, provenance, _) and
|
||||
pred = "summary"
|
||||
or
|
||||
neutralModel(namespace, type, name, signature, _, provenance) and
|
||||
@@ -268,11 +268,11 @@ module ModelValidation {
|
||||
private predicate elementSpec(
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
||||
) {
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _)
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
|
||||
or
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _)
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
|
||||
or
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _, _)
|
||||
or
|
||||
neutralModel(namespace, type, name, signature, _, _) and ext = "" and subtypes = false
|
||||
}
|
||||
@@ -393,14 +393,14 @@ Declaration interpretElement(
|
||||
* A callable where there exists a MaD sink model that applies to it.
|
||||
*/
|
||||
class SinkCallable extends Callable {
|
||||
SinkCallable() { SourceSinkInterpretationInput::sinkElement(this, _, _, _) }
|
||||
SinkCallable() { SourceSinkInterpretationInput::sinkElement(this, _, _, _, _) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A callable where there exists a MaD source model that applies to it.
|
||||
*/
|
||||
class SourceCallable extends Callable {
|
||||
SourceCallable() { SourceSinkInterpretationInput::sourceElement(this, _, _, _) }
|
||||
SourceCallable() { SourceSinkInterpretationInput::sourceElement(this, _, _, _, _) }
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -410,9 +410,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
|
||||
)
|
||||
}
|
||||
|
||||
@@ -421,15 +421,27 @@ 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, _) }
|
||||
|
||||
/** Holds if the summary should apply for all overrides of `c`. */
|
||||
predicate isBaseCallableOrPrototype(UnboundCallable c) {
|
||||
c.getDeclaringType() instanceof Interface
|
||||
@@ -517,12 +529,15 @@ string asPartialNeutralModel(UnboundCallable c) {
|
||||
}
|
||||
|
||||
private predicate interpretSummary(
|
||||
UnboundCallable c, string input, string output, string kind, string provenance
|
||||
UnboundCallable 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 namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
QlBuiltins::ExtensionId madId
|
||||
|
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
|
||||
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance,
|
||||
madId) and
|
||||
model = "MaD:" + madId.toString() and
|
||||
c = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
@@ -536,18 +551,22 @@ private predicate interpretNeutral(UnboundCallable c, string kind, string proven
|
||||
|
||||
// adapter class for converting Mad summaries to `SummarizedCallable`s
|
||||
private class SummarizedCallableAdapter extends SummarizedCallable {
|
||||
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _) }
|
||||
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _, _) }
|
||||
|
||||
private predicate relevantSummaryElementManual(string input, string output, string kind) {
|
||||
private predicate relevantSummaryElementManual(
|
||||
string input, string output, string kind, string model
|
||||
) {
|
||||
exists(Provenance provenance |
|
||||
interpretSummary(this, input, output, kind, provenance) and
|
||||
interpretSummary(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 |
|
||||
interpretSummary(this, input, output, kind, provenance) and
|
||||
interpretSummary(this, input, output, kind, provenance, model) and
|
||||
provenance.isGenerated()
|
||||
) and
|
||||
not exists(Provenance provenance |
|
||||
@@ -556,19 +575,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) {
|
||||
interpretSummary(this, _, _, _, provenance)
|
||||
interpretSummary(this, _, _, _, provenance, _)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*/
|
||||
extensible predicate sourceModel(
|
||||
string namespace, 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 namespace, 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 namespace, 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
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -169,20 +169,28 @@ module SourceSinkInterpretationInput implements
|
||||
|
||||
class Element = Cs::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
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
QlBuiltins::ExtensionId madId
|
||||
|
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
|
||||
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, madId) and
|
||||
model = "MaD:" + madId.toString() and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
|
||||
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
|
||||
string namespace, string type, boolean subtypes, string name, string signature, string ext,
|
||||
QlBuiltins::ExtensionId madId
|
||||
|
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance) and
|
||||
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, madId) and
|
||||
model = "MaD:" + madId.toString() and
|
||||
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
||||
)
|
||||
}
|
||||
@@ -380,10 +388,13 @@ private class SummarizedCallableWithCallback extends Public::SummarizedCallable
|
||||
|
||||
SummarizedCallableWithCallback() { mayInvokeCallback(this, 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[delegate-self]" and
|
||||
preservesValue = true
|
||||
preservesValue = true and
|
||||
model = "heuristic-callback"
|
||||
}
|
||||
|
||||
override predicate hasProvenance(Public::Provenance provenance) { provenance = "hq-generated" }
|
||||
|
||||
@@ -150,21 +150,24 @@ private module Cached {
|
||||
* in all global taint flow configurations.
|
||||
*/
|
||||
cached
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
|
||||
localTaintStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
// Taint members
|
||||
readStep(nodeFrom, any(TaintedMember m).(FieldOrProperty).getContent(), nodeTo)
|
||||
or
|
||||
// Although flow through collections is modeled precisely using stores/reads, we still
|
||||
// allow flow out of a _tainted_ collection. This is needed in order to support taint-
|
||||
// tracking configurations where the source is a collection
|
||||
readStep(nodeFrom, TElementContent(), nodeTo)
|
||||
predicate defaultAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo, string model) {
|
||||
(
|
||||
localTaintStepCommon(nodeFrom, nodeTo)
|
||||
or
|
||||
// Taint members
|
||||
readStep(nodeFrom, any(TaintedMember m).(FieldOrProperty).getContent(), nodeTo)
|
||||
or
|
||||
// Although flow through collections is modeled precisely using stores/reads, we still
|
||||
// allow flow out of a _tainted_ collection. This is needed in order to support taint-
|
||||
// tracking configurations where the source is a collection
|
||||
readStep(nodeFrom, TElementContent(), nodeTo)
|
||||
or
|
||||
nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false)
|
||||
) and
|
||||
model = ""
|
||||
or
|
||||
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), false)
|
||||
or
|
||||
nodeTo = nodeFrom.(DataFlow::NonLocalJumpNode).getAJumpSuccessor(false)
|
||||
nodeTo.(FlowSummaryNode).getSummaryNode(), false, model)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,9 @@ module EntityFramework {
|
||||
// see `SummarizedCallableImpl` qldoc
|
||||
private class EFSummarizedCallableAdapter extends SummarizedCallable instanceof EFSummarizedCallable
|
||||
{
|
||||
override predicate propagatesFlow(string input, string output, boolean preservesValue) {
|
||||
override predicate propagatesFlow(
|
||||
string input, string output, boolean preservesValue, string model
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
@@ -174,11 +176,13 @@ module EntityFramework {
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
) {
|
||||
input = SummaryComponentStack::argument(0) and
|
||||
output = SummaryComponentStack::return() and
|
||||
preservesValue = false
|
||||
preservesValue = false and
|
||||
model = "RawSqlStringConstructorSummarizedCallable"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,11 +192,13 @@ module EntityFramework {
|
||||
}
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
) {
|
||||
input = SummaryComponentStack::argument(0) and
|
||||
output = SummaryComponentStack::return() and
|
||||
preservesValue = false
|
||||
preservesValue = false and
|
||||
model = "RawSqlStringConversionSummarizedCallable"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,12 +469,14 @@ module EntityFramework {
|
||||
DbContextClassSetPropertySynthetic() { this = p.getGetter() }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
) {
|
||||
exists(string name, DbContextClass c |
|
||||
preservesValue = true and
|
||||
name = c.getSyntheticName(output, _, p) and
|
||||
input = SummaryComponentStack::syntheticGlobal(name)
|
||||
input = SummaryComponentStack::syntheticGlobal(name) and
|
||||
model = "DbContextClassSetPropertySynthetic"
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -479,13 +487,15 @@ module EntityFramework {
|
||||
DbContextSaveChanges() { this = c.getASaveChanges() }
|
||||
|
||||
override predicate propagatesFlow(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
|
||||
string model
|
||||
) {
|
||||
exists(string name, Property mapped |
|
||||
preservesValue = true and
|
||||
c.input(input, mapped) and
|
||||
name = c.getSyntheticName(_, mapped, _) and
|
||||
output = SummaryComponentStack::syntheticGlobal(name)
|
||||
output = SummaryComponentStack::syntheticGlobal(name) and
|
||||
model = "DbContextSaveChanges"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ class ExternalApi extends Callable {
|
||||
predicate hasSummary() {
|
||||
this instanceof SummarizedCallable
|
||||
or
|
||||
defaultAdditionalTaintStep(this.getAnInput(), _)
|
||||
defaultAdditionalTaintStep(this.getAnInput(), _, _)
|
||||
}
|
||||
|
||||
/** Holds if this API is a known source. */
|
||||
|
||||
@@ -12,7 +12,7 @@ from
|
||||
string name, string signature0, string signature, string ext, string input, string kind,
|
||||
string provenance
|
||||
where
|
||||
sinkModel(namespace0, type0, subtypes, name0, signature0, ext, input, kind, provenance) and
|
||||
sinkModel(namespace0, type0, subtypes, name0, signature0, ext, input, kind, provenance, _) and
|
||||
interpretCallable(namespace0, namespace, type0, type, name0, name, signature0, signature)
|
||||
select namespace, type, subtypes, name, signature, ext, input, kind, provenance order by
|
||||
namespace, type, name, signature, input, kind
|
||||
|
||||
@@ -12,7 +12,7 @@ from
|
||||
string name, string signature0, string signature, string ext, string output, string kind,
|
||||
string provenance
|
||||
where
|
||||
sourceModel(namespace0, type0, subtypes, name0, signature0, ext, output, kind, provenance) and
|
||||
sourceModel(namespace0, type0, subtypes, name0, signature0, ext, output, kind, provenance, _) and
|
||||
interpretCallable(namespace0, namespace, type0, type, name0, name, signature0, signature)
|
||||
select namespace, type, subtypes, name, signature, ext, output, kind, provenance order by
|
||||
namespace, type, name, signature, output, kind
|
||||
|
||||
@@ -12,7 +12,8 @@ from
|
||||
string name, string signature0, string signature, string ext, string input, string output,
|
||||
string kind, string provenance
|
||||
where
|
||||
summaryModel(namespace0, type0, subtypes, name0, signature0, ext, input, output, kind, provenance) and
|
||||
summaryModel(namespace0, type0, subtypes, name0, signature0, ext, input, output, kind, provenance,
|
||||
_) and
|
||||
interpretCallable(namespace0, namespace, type0, type, name0, name, signature0, signature)
|
||||
select namespace, type, subtypes, name, signature, ext, input, output, kind, provenance order by
|
||||
namespace, type, name, signature, input, output, kind
|
||||
|
||||
@@ -34,7 +34,7 @@ class ExternalEndpoint extends Endpoint {
|
||||
override predicate hasSummary() {
|
||||
Endpoint.super.hasSummary()
|
||||
or
|
||||
defaultAdditionalTaintStep(this.getAnInput(), _)
|
||||
defaultAdditionalTaintStep(this.getAnInput(), _, _)
|
||||
}
|
||||
|
||||
override predicate isSource() {
|
||||
|
||||
@@ -10,10 +10,10 @@ class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
|
||||
override predicate relevantSummary(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
this.propagatesFlow(input, output, preservesValue) and
|
||||
this.propagatesFlow(input, output, preservesValue, _) and
|
||||
not exists(IncludeSummarizedCallable rsc |
|
||||
isBaseCallableOrPrototype(rsc) and
|
||||
rsc.propagatesFlow(input, output, preservesValue) and
|
||||
rsc.propagatesFlow(input, output, preservesValue, _) and
|
||||
this.(UnboundCallable).overridesOrImplementsUnbound(rsc)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,6 @@ class IncludeSummarizedCallable extends SummarizedCallableImplFinal {
|
||||
predicate relevantSummary(
|
||||
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
|
||||
) {
|
||||
this.propagatesFlow(input, output, preservesValue)
|
||||
this.propagatesFlow(input, output, preservesValue, _)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user