Skip to content
Draft
44 changes: 13 additions & 31 deletions cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -1058,40 +1058,22 @@ private predicate interpretSummary(

// adapter class for converting Mad summaries to `SummarizedCallable`s
private class SummarizedCallableAdapter extends SummarizedCallable {
SummarizedCallableAdapter() { interpretSummary(this, _, _, _, _, _) }
string input_;
string output_;
string kind;
Provenance p_;
string model_;

private predicate relevantSummaryElementManual(
string input, string output, string kind, string model
) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and
provenance.isManual()
)
}

private predicate relevantSummaryElementGenerated(
string input, string output, string kind, string model
) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and
provenance.isGenerated()
)
}
SummarizedCallableAdapter() { interpretSummary(this, input_, output_, kind, p_, model_) }

override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
string input, string output, boolean preservesValue, Provenance p, boolean isExact, string model
) {
exists(string kind |
this.relevantSummaryElementManual(input, output, kind, model)
or
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, _)
input = input_ and
output = output_ and
(if kind = "value" then preservesValue = true else preservesValue = false) and
p = p_ and
isExact = true and
model = model_
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1144,7 +1144,7 @@ private newtype TDataFlowCall =
}

private predicate summarizedCallableIsManual(SummarizedCallable sc) {
sc.asSummarizedCallable().applyManualModel()
sc.asSummarizedCallable().hasManualModel()
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ private module SummaryModelGeneratorInput implements SummaryModelGeneratorInputS
}

private predicate hasManualSummaryModel(Callable api) {
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.hasManualModel()) or
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,24 +371,9 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
/** Gets the underlying call. */
DispatchCall getDispatchCall() { result = dc }

pragma[nomagic]
private predicate hasSourceTarget() { dc.getAStaticTarget().fromSource() }

pragma[nomagic]
private FlowSummary::SummarizedCallable getASummarizedCallableTarget() {
// Only use summarized callables with generated summaries in case
// we are not able to dispatch to a source declaration.
exists(boolean static |
result = this.getATarget(static) and
not (
result.applyGeneratedModel() and
this.hasSourceTarget()
)
|
static = false
or
static = true and not result instanceof RuntimeCallable
)
result = this.getATarget(_)
}

pragma[nomagic]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ private predicate fieldOrPropertyStore(Expr e, ContentSet c, Expr src, Expr q, b
FlowSummaryImpl::Private::SummarizedCallableImpl sc,
FlowSummaryImpl::Private::SummaryComponentStack input, ContentSet readSet
|
sc.propagatesFlow(input, _, _, _) and
sc.propagatesFlow(input, _, _, _, _, _) and
input.contains(FlowSummaryImpl::Private::SummaryComponent::content(readSet)) and
c.getAStoreContent() = readSet.getAReadContent()
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -349,20 +349,23 @@ private Declaration interpretExt(Declaration d, ExtPath ext) {
/** Gets the source/sink/summary/neutral element corresponding to the supplied parameters. */
pragma[nomagic]
Declaration interpretElement(
string namespace, string type, boolean subtypes, string name, string signature, string ext
string namespace, string type, boolean subtypes, string name, string signature, string ext,
boolean isExact
) {
elementSpec(namespace, type, subtypes, name, signature, ext) and
exists(Declaration base, Declaration d |
base = interpretBaseDeclaration(namespace, type, name, signature) and
(
d = base
d = base and
isExact = true
or
subtypes = true and
(
d.(UnboundCallable).overridesOrImplementsUnbound(base)
or
d = base.(UnboundValueOrRefType).getASubTypeUnbound+()
)
) and
isExact = false
)
|
result = interpretExt(d, ext)
Expand Down Expand Up @@ -500,71 +503,47 @@ string getSignature(UnboundCallable c) {
}

private predicate interpretSummary(
UnboundCallable c, string input, string output, string kind, string provenance, string model
UnboundCallable c, string input, string output, string kind, string provenance, boolean isExact,
string model
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance,
model) and
c = interpretElement(namespace, type, subtypes, name, signature, ext)
c = interpretElement(namespace, type, subtypes, name, signature, ext, isExact)
)
}

predicate interpretNeutral(UnboundCallable c, string kind, string provenance) {
predicate interpretNeutral(UnboundCallable c, string kind, string provenance, boolean isExact) {
exists(string namespace, string type, string name, string signature |
Extensions::neutralModel(namespace, type, name, signature, kind, provenance) and
c = interpretElement(namespace, type, true, name, signature, "")
c = interpretElement(namespace, type, true, name, signature, "", isExact)
)
}

// adapter class for converting Mad summaries to `SummarizedCallable`s
private class SummarizedCallableAdapter extends SummarizedCallable {
SummarizedCallableAdapter() {
exists(Provenance provenance | interpretSummary(this, _, _, _, provenance, _) |
not this.fromSource()
or
this.fromSource() and provenance.isManual()
)
}

private predicate relevantSummaryElementManual(
string input, string output, string kind, string model
) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and
provenance.isManual()
)
}
string input_;
string output_;
string kind;
Provenance p_;
boolean isExact_;
string model_;

private predicate relevantSummaryElementGenerated(
string input, string output, string kind, string model
) {
exists(Provenance provenance |
interpretSummary(this, input, output, kind, provenance, model) and
provenance.isGenerated()
) and
not exists(Provenance provenance |
interpretNeutral(this, "summary", provenance) and
provenance.isManual()
)
SummarizedCallableAdapter() {
interpretSummary(this, input_, output_, kind, p_, isExact_, model_)
}

override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
string input, string output, boolean preservesValue, Provenance p, boolean isExact, string model
) {
exists(string kind |
this.relevantSummaryElementManual(input, output, kind, model)
or
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, _)
input = input_ and
output = output_ and
(if kind = "value" then preservesValue = true else preservesValue = false) and
p = p_ and
isExact = isExact_ and
model = model_
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CsharpDataFlow>

class SummarizedCallableBase = UnboundCallable;

predicate allowGeneratedSummary(SummarizedCallableBase c) { not c.fromSource() }

class SourceBase = Void;

class SinkBase = Void;

predicate neutralElement(SummarizedCallableBase c, string kind, string provenance, boolean isExact) {
interpretNeutral(c, kind, provenance) and
interpretNeutral(c, kind, provenance, _) and
// isExact is not needed for C#.
isExact = false
}
Expand Down Expand Up @@ -216,7 +218,7 @@ module SourceSinkInterpretationInput implements
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
e = interpretElement(namespace, type, subtypes, name, signature, ext, _)
)
}

Expand All @@ -227,7 +229,7 @@ module SourceSinkInterpretationInput implements
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, model) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
e = interpretElement(namespace, type, subtypes, name, signature, ext, _)
)
}

Expand Down Expand Up @@ -437,13 +439,14 @@ private class SummarizedCallableWithCallback extends Public::SummarizedCallable
SummarizedCallableWithCallback() { mayInvokeCallback(this, pos) }

override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
string input, string output, boolean preservesValue, Public::Provenance provenance,
boolean isExact, string model
) {
input = "Argument[" + pos + "]" and
output = "Argument[" + pos + "].Parameter[delegate-self]" and
preservesValue = true and
provenance = "hq-generated" and
isExact = true and
model = "heuristic-callback"
}

override predicate hasProvenance(Public::Provenance provenance) { provenance = "hq-generated" }
}
31 changes: 17 additions & 14 deletions csharp/ql/lib/semmle/code/csharp/frameworks/EntityFramework.qll
Original file line number Diff line number Diff line change
Expand Up @@ -92,22 +92,17 @@ module EntityFramework {
abstract class EFSummarizedCallable extends SummarizedCallableImpl {
bindingset[this]
EFSummarizedCallable() { any() }

override predicate hasProvenance(Provenance provenance) { provenance = "manual" }
}

// see `SummarizedCallableImpl` qldoc
private class EFSummarizedCallableAdapter extends SummarizedCallable instanceof EFSummarizedCallable
{
override predicate propagatesFlow(
string input, string output, boolean preservesValue, string model
string input, string output, boolean preservesValue, Provenance provenance, boolean isExact,
string model
) {
none()
}

override predicate hasProvenance(Provenance provenance) {
EFSummarizedCallable.super.hasProvenance(provenance)
}
}

/** The class ``Microsoft.EntityFrameworkCore.DbQuery`1`` or ``System.Data.Entity.DbQuery`1``. */
Expand Down Expand Up @@ -177,11 +172,13 @@ module EntityFramework {

override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
string model
Provenance p, boolean isExact, string model
) {
input = SummaryComponentStack::argument(0) and
output = SummaryComponentStack::return() and
preservesValue = false and
p = "manual" and
isExact = true and
model = "RawSqlStringConstructorSummarizedCallable"
}
}
Expand All @@ -193,11 +190,13 @@ module EntityFramework {

override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
string model
Provenance p, boolean isExact, string model
) {
input = SummaryComponentStack::argument(0) and
output = SummaryComponentStack::return() and
preservesValue = false and
p = "manual" and
isExact = true and
model = "RawSqlStringConversionSummarizedCallable"
}
}
Expand Down Expand Up @@ -459,18 +458,20 @@ module EntityFramework {
}

private class DbContextClassSetPropertySynthetic extends EFSummarizedCallable {
private DbContextClassSetProperty p;
private DbContextClassSetProperty prop;

DbContextClassSetPropertySynthetic() { this = p.getGetter() }
DbContextClassSetPropertySynthetic() { this = prop.getGetter() }

override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
string model
Provenance p, boolean isExact, string model
) {
exists(string name, DbContextClass c |
preservesValue = true and
name = c.getSyntheticName(output, _, p) and
name = c.getSyntheticName(output, _, prop) and
input = SummaryComponentStack::syntheticGlobal(name) and
p = "manual" and
isExact = true and
model = "DbContextClassSetPropertySynthetic"
)
}
Expand All @@ -483,13 +484,15 @@ module EntityFramework {

override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue,
string model
Provenance p, boolean isExact, string model
) {
exists(string name, Property mapped |
preservesValue = true and
c.input(input, mapped) and
name = c.getSyntheticNameProj(mapped) and
output = SummaryComponentStack::syntheticGlobal(name) and
p = "manual" and
isExact = true and
model = "DbContextSaveChanges"
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ module SummaryModelGeneratorInput implements SummaryModelGeneratorInputSig {
}

private predicate hasManualSummaryModel(Callable api) {
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.applyManualModel()) or
api = any(FlowSummaryImpl::Public::SummarizedCallable sc | sc.hasManualModel()) or
api = any(FlowSummaryImpl::Public::NeutralSummaryCallable sc | sc.hasManualModel())
}

Expand Down
Loading
Loading