Merge pull request #9014 from michaelnebel/csharp/dataflowcallablerefactor

C#: Dataflow callable refactoring.
This commit is contained in:
Tom Hvitved
2022-05-19 09:02:38 +02:00
committed by GitHub
16 changed files with 284 additions and 106 deletions

View File

@@ -515,8 +515,10 @@ Element interpretElement(
/**
* Holds if `c` has a `generated` summary.
*/
predicate hasSummary(DataFlowCallable c, boolean generated) {
summaryElement(c, _, _, _, generated)
predicate hasSummary(Callable c, boolean generated) {
exists(DataFlowCallable dc |
dc.asSummarizedCallable() = c and summaryElement(dc, _, _, _, generated)
)
}
cached

View File

@@ -1,6 +1,7 @@
/** Provides classes and predicates for defining flow summaries. */
import csharp
private import dotnet
private import internal.FlowSummaryImpl as Impl
private import internal.DataFlowDispatch as DataFlowDispatch
@@ -113,7 +114,69 @@ module SummaryComponentStack {
SummaryComponentStack jump(Callable c) { result = singleton(SummaryComponent::jump(c)) }
}
class SummarizedCallable = Impl::Public::SummarizedCallable;
/**
* A class for synthesized callables given by a summary.
*/
abstract class SummarizedCallable extends DotNet::Callable {
SummarizedCallable() { this.isUnboundDeclaration() }
/**
* Holds if data may flow from `input` to `output` through this callable.
*
* `preservesValue` indicates whether this is a value-preserving step
* or a taint-step.
*
* Input specifications are restricted to stacks that end with
* `SummaryComponent::argument(_)`, preceded by zero or more
* `SummaryComponent::return(_)` or `SummaryComponent::content(_)` components.
*
* Output specifications are restricted to stacks that end with
* `SummaryComponent::return(_)` or `SummaryComponent::argument(_)`.
*
* Output stacks ending with `SummaryComponent::return(_)` can be preceded by zero
* or more `SummaryComponent::content(_)` components.
*
* Output stacks ending with `SummaryComponent::argument(_)` can be preceded by an
* optional `SummaryComponent::parameter(_)` component, which in turn can be preceded
* by zero or more `SummaryComponent::content(_)` components.
*/
pragma[nomagic]
predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
none()
}
/**
* Holds if values stored inside `content` are cleared on objects passed as
* arguments at position `pos` to this callable.
*/
pragma[nomagic]
predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) { none() }
/**
* Holds if the summary is auto generated.
*/
predicate isAutoGenerated() { none() }
}
private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable {
private SummarizedCallable sc;
SummarizedCallableAdapter() { this = DataFlowDispatch::TSummarizedCallable(sc) }
final override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
sc.propagatesFlow(input, output, preservesValue)
}
final override predicate clearsContent(ParameterPosition pos, DataFlow::ContentSet content) {
sc.clearsContent(pos, content)
}
final override predicate isAutoGenerated() { sc.isAutoGenerated() }
}
private predicate recordConstructorFlow(Constructor c, int i, Property p) {
c = any(RecordType r).getAMember() and

View File

@@ -12,14 +12,6 @@ private import semmle.code.csharp.dispatch.RuntimeCallable
private import semmle.code.csharp.frameworks.system.Collections
private import semmle.code.csharp.frameworks.system.collections.Generic
private predicate summarizedCallable(DataFlowCallable c) {
c instanceof FlowSummary::SummarizedCallable
or
FlowSummaryImpl::Private::summaryReturnNode(_, TJumpReturnKind(c, _))
or
c = interpretElement(_, _, _, _, _, _)
}
/**
* Gets a source declaration of callable `c` that has a body or has
* a flow summary.
@@ -29,9 +21,6 @@ private predicate summarizedCallable(DataFlowCallable c) {
*/
DotNet::Callable getCallableForDataFlow(DotNet::Callable c) {
exists(DotNet::Callable unboundDecl | unboundDecl = c.getUnboundDeclaration() |
summarizedCallable(unboundDecl) and
result = unboundDecl
or
result.hasBody() and
if unboundDecl.getFile().fromSource()
then
@@ -81,17 +70,27 @@ newtype TReturnKind =
v = def.getSourceVariable().getAssignable()
)
} or
TJumpReturnKind(DataFlowCallable target, ReturnKind rk) {
rk instanceof NormalReturnKind and
TJumpReturnKind(Callable target, ReturnKind rk) {
target.isUnboundDeclaration() and
(
target instanceof Constructor or
not target.getReturnType() instanceof VoidType
rk instanceof NormalReturnKind and
(
target instanceof Constructor or
not target.getReturnType() instanceof VoidType
)
or
exists(target.getParameter(rk.(OutRefReturnKind).getPosition()))
)
or
exists(target.getParameter(rk.(OutRefReturnKind).getPosition()))
}
private module Cached {
cached
newtype TDataFlowCallable =
TDotNetCallable(DotNet::Callable c) {
c.isUnboundDeclaration() and not c instanceof FlowSummary::SummarizedCallable
} or
TSummarizedCallable(FlowSummary::SummarizedCallable c)
cached
newtype TDataFlowCall =
TNonDelegateCall(ControlFlow::Nodes::ElementNode cfn, DispatchCall dc) {
@@ -108,7 +107,7 @@ private module Cached {
// No need to include calls that are compiled from source
not call.getImplementation().getMethod().compiledFromSource()
} or
TSummaryCall(FlowSummary::SummarizedCallable c, Node receiver) {
TSummaryCall(FlowSummaryImpl::Public::SummarizedCallable c, Node receiver) {
FlowSummaryImpl::Private::summaryCallbackRange(c, receiver)
}
@@ -144,7 +143,7 @@ private module DispatchImpl {
* call is a delegate call, or if the qualifier accesses a parameter of
* the enclosing callable `c` (including the implicit `this` parameter).
*/
predicate mayBenefitFromCallContext(NonDelegateDataFlowCall call, Callable c) {
predicate mayBenefitFromCallContext(NonDelegateDataFlowCall call, DataFlowCallable c) {
c = call.getEnclosingCallable() and
call.getDispatchCall().mayBenefitFromCallContext()
}
@@ -154,7 +153,7 @@ private module DispatchImpl {
* restricted to those `call`s for which a context might make a difference.
*/
DataFlowCallable viableImplInCallContext(NonDelegateDataFlowCall call, DataFlowCall ctx) {
result =
result.getUnderlyingCallable() =
call.getDispatchCall()
.getADynamicTargetInCallContext(ctx.(NonDelegateDataFlowCall).getDispatchCall())
.getUnboundDeclaration()
@@ -233,13 +232,13 @@ class ImplicitCapturedReturnKind extends ReturnKind, TImplicitCapturedReturnKind
* one API entry point and out of another.
*/
class JumpReturnKind extends ReturnKind, TJumpReturnKind {
private DataFlowCallable target;
private Callable target;
private ReturnKind rk;
JumpReturnKind() { this = TJumpReturnKind(target, rk) }
/** Gets the target of the jump. */
DataFlowCallable getTarget() { result = target }
Callable getTarget() { result = target }
/** Gets the return kind of the target. */
ReturnKind getTargetReturnKind() { result = rk }
@@ -247,8 +246,24 @@ class JumpReturnKind extends ReturnKind, TJumpReturnKind {
override string toString() { result = "jump to " + target }
}
class DataFlowCallable extends DotNet::Callable {
DataFlowCallable() { this.isUnboundDeclaration() }
/** A callable used for data flow. */
class DataFlowCallable extends TDataFlowCallable {
/** Get the underlying source code callable, if any. */
DotNet::Callable asCallable() { this = TDotNetCallable(result) }
/** Get the underlying summarized callable, if any. */
FlowSummary::SummarizedCallable asSummarizedCallable() { this = TSummarizedCallable(result) }
/** Get the underlying callable. */
DotNet::Callable getUnderlyingCallable() {
result = this.asCallable() or result = this.asSummarizedCallable()
}
/** Gets a textual representation of this dataflow callable. */
string toString() { result = this.getUnderlyingCallable().toString() }
/** Get the location of this dataflow callable. */
Location getLocation() { result = this.getUnderlyingCallable().getLocation() }
}
/** A call relevant for data flow. */
@@ -306,18 +321,32 @@ class NonDelegateDataFlowCall extends DataFlowCall, TNonDelegateCall {
DispatchCall getDispatchCall() { result = dc }
override DataFlowCallable getARuntimeTarget() {
result = getCallableForDataFlow(dc.getADynamicTarget())
result.asCallable() = getCallableForDataFlow(dc.getADynamicTarget())
or
result = dc.getAStaticTarget().getUnboundDeclaration() and
summarizedCallable(result) and
not result instanceof RuntimeCallable
exists(Callable c, boolean static |
result.asSummarizedCallable() = c and
c = this.getATarget(static)
|
static = false
or
static = true and not c instanceof RuntimeCallable
)
}
/** Gets a static or dynamic target of this call. */
Callable getATarget(boolean static) {
result = dc.getADynamicTarget().getUnboundDeclaration() and static = false
or
result = dc.getAStaticTarget().getUnboundDeclaration() and static = true
}
override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
}
override string toString() { result = cfn.toString() }
@@ -345,7 +374,9 @@ class ExplicitDelegateLikeDataFlowCall extends DelegateDataFlowCall, TExplicitDe
override DataFlow::ExprNode getNode() { result.getControlFlowNode() = cfn }
override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
}
override string toString() { result = cfn.toString() }
@@ -363,13 +394,15 @@ class TransitiveCapturedDataFlowCall extends DataFlowCall, TTransitiveCapturedCa
TransitiveCapturedDataFlowCall() { this = TTransitiveCapturedCall(cfn, target) }
override DataFlowCallable getARuntimeTarget() { result = target }
override DataFlowCallable getARuntimeTarget() { result.getUnderlyingCallable() = target }
override ControlFlow::Nodes::ElementNode getControlFlowNode() { result = cfn }
override DataFlow::ExprNode getNode() { none() }
override DataFlowCallable getEnclosingCallable() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
}
override string toString() { result = "[transitive] " + cfn.toString() }
@@ -384,14 +417,16 @@ class CilDataFlowCall extends DataFlowCall, TCilCall {
override DataFlowCallable getARuntimeTarget() {
// There is no dispatch library for CIL, so do not consider overrides for now
result = getCallableForDataFlow(call.getTarget())
result.getUnderlyingCallable() = getCallableForDataFlow(call.getTarget())
}
override ControlFlow::Nodes::ElementNode getControlFlowNode() { none() }
override DataFlow::ExprNode getNode() { result.getExpr() = call }
override DataFlowCallable getEnclosingCallable() { result = call.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallable() {
result.getUnderlyingCallable() = call.getEnclosingCallable()
}
override string toString() { result = call.toString() }
@@ -406,7 +441,7 @@ class CilDataFlowCall extends DataFlowCall, TCilCall {
* the method `Select`.
*/
class SummaryCall extends DelegateDataFlowCall, TSummaryCall {
private FlowSummary::SummarizedCallable c;
private FlowSummaryImpl::Public::SummarizedCallable c;
private Node receiver;
SummaryCall() { this = TSummaryCall(c, receiver) }

View File

@@ -19,7 +19,7 @@ private import semmle.code.csharp.frameworks.system.Collections
private import semmle.code.csharp.frameworks.system.threading.Tasks
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallableImpl() }
/** Holds if `p` is a `ParameterNode` of `c` with position `pos`. */
predicate isParameterNode(ParameterNodeImpl p, DataFlowCallable c, ParameterPosition pos) {
@@ -65,9 +65,9 @@ abstract class NodeImpl extends Node {
private class ExprNodeImpl extends ExprNode, NodeImpl {
override DataFlowCallable getEnclosingCallableImpl() {
result = this.getExpr().(CIL::Expr).getEnclosingCallable()
result.getUnderlyingCallable() = this.getExpr().(CIL::Expr).getEnclosingCallable()
or
result = this.getControlFlowNodeImpl().getEnclosingCallable()
result.getUnderlyingCallable() = this.getControlFlowNodeImpl().getEnclosingCallable()
}
override DotNet::Type getTypeImpl() {
@@ -506,10 +506,10 @@ private predicate fieldOrPropertyStore(Expr e, Content c, Expr src, Expr q, bool
f instanceof InstanceFieldOrProperty
or
exists(
FlowSummary::SummarizedCallable callable,
FlowSummaryImpl::Public::SummarizedCallable sc,
FlowSummaryImpl::Public::SummaryComponentStack input
|
callable.propagatesFlow(input, _, _) and
sc.propagatesFlow(input, _, _) and
input.contains(FlowSummary::SummaryComponent::content(f.getContent()))
)
)
@@ -693,9 +693,12 @@ private module Cached {
not def.(Ssa::ExplicitDefinition).getADefinition() instanceof
AssignableDefinitions::ImplicitParameterDefinition
} or
TExplicitParameterNode(DotNet::Parameter p) { p = any(DataFlowCallable c).getAParameter() } or
TExplicitParameterNode(DotNet::Parameter p) {
p = any(DataFlowCallable dfc).asCallable().getAParameter()
} or
TInstanceParameterNode(Callable c) {
c.isUnboundDeclaration() and not c.(Modifiable).isStatic()
c = any(DataFlowCallable dfc).asCallable() and
not c.(Modifiable).isStatic()
} or
TYieldReturnNode(ControlFlow::Nodes::ElementNode cfn) {
any(Callable c).canYieldReturn(cfn.getElement())
@@ -736,9 +739,15 @@ private module Cached {
)
)
} or
TSummaryNode(FlowSummary::SummarizedCallable c, FlowSummaryImpl::Private::SummaryNodeState state) {
TSummaryNode(
FlowSummaryImpl::Public::SummarizedCallable c,
FlowSummaryImpl::Private::SummaryNodeState state
) {
FlowSummaryImpl::Private::summaryNodeRange(c, state)
} or
TSummaryParameterNode(FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition pos) {
FlowSummaryImpl::Private::summaryParameterNodeRange(c, pos)
} or
TParamsArgumentNode(ControlFlow::Node callCfn) {
callCfn = any(Call c | isParamsArg(c, _, _)).getAControlFlowNode()
}
@@ -810,11 +819,7 @@ predicate nodeIsHidden(Node n) {
def instanceof Ssa::ImplicitCallDefinition
)
or
exists(Parameter p | p = n.(ParameterNode).getParameter() |
not p.fromSource()
or
p.getCallable() instanceof FlowSummary::SummarizedCallable
)
exists(Parameter p | p = n.(ParameterNode).getParameter() | not p.fromSource())
or
n =
TInstanceParameterNode(any(Callable c |
@@ -831,6 +836,8 @@ predicate nodeIsHidden(Node n) {
or
n instanceof SummaryNode
or
n instanceof SummaryParameterNode
or
n instanceof ParamsArgumentNode
or
n.asExpr() = any(WithExpr we).getInitializer()
@@ -845,7 +852,9 @@ class SsaDefinitionNode extends NodeImpl, TSsaDefinitionNode {
/** Gets the underlying SSA definition. */
Ssa::Definition getDefinition() { result = def }
override DataFlowCallable getEnclosingCallableImpl() { result = def.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = def.getEnclosingCallable()
}
override Type getTypeImpl() { result = def.getSourceVariable().getType() }
@@ -877,10 +886,12 @@ private module ParameterNodes {
}
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
c.getParameter(pos.getPosition()) = parameter
c.asCallable().getParameter(pos.getPosition()) = parameter
}
override DataFlowCallable getEnclosingCallableImpl() { result = parameter.getCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.asCallable() = parameter.getCallable()
}
override DotNet::Type getTypeImpl() { result = parameter.getType() }
@@ -901,10 +912,12 @@ private module ParameterNodes {
Callable getCallable() { result = callable }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
callable = c and pos.isThisParameter()
callable = c.asCallable() and pos.isThisParameter()
}
override DataFlowCallable getEnclosingCallableImpl() { result = callable }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = callable
}
override Type getTypeImpl() { result = callable.getDeclaringType() }
@@ -951,9 +964,37 @@ private module ParameterNodes {
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
pos.isImplicitCapturedParameterPosition(def.getSourceVariable().getAssignable()) and
c = this.getEnclosingCallable()
c.getUnderlyingCallable() = this.getEnclosingCallable()
}
}
/** A parameter for a library callable with a flow summary. */
class SummaryParameterNode extends ParameterNodeImpl, TSummaryParameterNode {
private FlowSummaryImpl::Public::SummarizedCallable sc;
private ParameterPosition pos_;
SummaryParameterNode() { this = TSummaryParameterNode(sc, pos_) }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
sc = c and pos = pos_
}
override DataFlowCallable getEnclosingCallableImpl() { result = sc }
override Type getTypeImpl() {
exists(int i |
pos_.getPosition() = i and result = sc.asSummarizedCallable().getParameter(i).getType()
)
or
pos_.isThisParameter() and result = sc.asSummarizedCallable().getDeclaringType()
}
override ControlFlow::Node getControlFlowNodeImpl() { none() }
override EmptyLocation getLocationImpl() { any() }
override string toStringImpl() { result = "parameter " + pos_ + " of " + sc }
}
}
import ParameterNodes
@@ -1039,7 +1080,9 @@ private module ArgumentNodes {
call.getControlFlowNode() = cfn
}
override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
}
override Type getTypeImpl() { result = v.getType() }
@@ -1066,7 +1109,9 @@ private module ArgumentNodes {
override ControlFlow::Node getControlFlowNodeImpl() { result = cfn }
override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
}
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
@@ -1103,7 +1148,9 @@ private module ArgumentNodes {
pos.getPosition() = this.getParameter().getPosition()
}
override DataFlowCallable getEnclosingCallableImpl() { result = callCfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = callCfn.getEnclosingCallable()
}
override Type getTypeImpl() { result = this.getParameter().getType() }
@@ -1182,7 +1229,9 @@ private module ReturnNodes {
override NormalReturnKind getKind() { any() }
override DataFlowCallable getEnclosingCallableImpl() { result = yrs.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = yrs.getEnclosingCallable()
}
override Type getTypeImpl() { result = yrs.getEnclosingCallable().getReturnType() }
@@ -1206,7 +1255,9 @@ private module ReturnNodes {
override NormalReturnKind getKind() { any() }
override DataFlowCallable getEnclosingCallableImpl() { result = expr.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = expr.getEnclosingCallable()
}
override Type getTypeImpl() { result = expr.getEnclosingCallable().getReturnType() }
@@ -1408,7 +1459,7 @@ import OutNodes
/** A data-flow node used to model flow summaries. */
class SummaryNode extends NodeImpl, TSummaryNode {
private FlowSummary::SummarizedCallable c;
private FlowSummaryImpl::Public::SummarizedCallable c;
private FlowSummaryImpl::Private::SummaryNodeState state;
SummaryNode() { this = TSummaryNode(c, state) }
@@ -1504,9 +1555,9 @@ predicate jumpStep(Node pred, Node succ) {
flr.hasNonlocalValue()
)
or
exists(JumpReturnKind jrk, DataFlowCall call |
exists(JumpReturnKind jrk, NonDelegateDataFlowCall call |
FlowSummaryImpl::Private::summaryReturnNode(pred, jrk) and
viableCallable(call) = jrk.getTarget() and
jrk.getTarget() = call.getATarget(_) and
succ = getAnOutNode(call, jrk.getTargetReturnKind())
)
}
@@ -1854,7 +1905,9 @@ private module PostUpdateNodes {
.hasExprPath(_, cfn, _, call.getControlFlowNode())
}
override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
}
override DotNet::Type getTypeImpl() { result = oc.getType() }
@@ -1872,7 +1925,9 @@ private module PostUpdateNodes {
override ExprNode getPreUpdateNode() { cfn = result.getControlFlowNode() }
override DataFlowCallable getEnclosingCallableImpl() { result = cfn.getEnclosingCallable() }
override DataFlowCallable getEnclosingCallableImpl() {
result.getUnderlyingCallable() = cfn.getEnclosingCallable()
}
override Type getTypeImpl() { result = cfn.getElement().(Expr).getType() }
@@ -1960,11 +2015,12 @@ class LambdaCallKind = Unit;
/** Holds if `creation` is an expression that creates a delegate for `c`. */
predicate lambdaCreation(ExprNode creation, LambdaCallKind kind, DataFlowCallable c) {
exists(Expr e | e = creation.getExpr() |
c = e.(AnonymousFunctionExpr)
c.getUnderlyingCallable() = e.(AnonymousFunctionExpr)
or
c = e.(CallableAccess).getTarget().getUnboundDeclaration()
c.getUnderlyingCallable() = e.(CallableAccess).getTarget().getUnboundDeclaration()
or
c = e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
c.getUnderlyingCallable() =
e.(AddressOfExpr).getOperand().(CallableAccess).getTarget().getUnboundDeclaration()
) and
kind = TMkUnit()
}
@@ -2047,7 +2103,7 @@ abstract class SyntheticField extends string {
predicate containerContent(DataFlow::Content c) { c instanceof DataFlow::ElementContent }
/** Gets the string representation of the parameters of `c`. */
string parameterQualifiedTypeNamesToString(DataFlowCallable c) {
string parameterQualifiedTypeNamesToString(DotNet::Callable c) {
result =
concat(Parameter p, int i |
p = c.getParameter(i)
@@ -2061,7 +2117,7 @@ string parameterQualifiedTypeNamesToString(DataFlowCallable c) {
*/
module Csv {
/** Holds if the summary should apply for all overrides of `c`. */
predicate isBaseCallableOrPrototype(DataFlowCallable c) {
predicate isBaseCallableOrPrototype(DotNet::Callable c) {
c.getDeclaringType() instanceof Interface
or
exists(Modifiable m | m = [c.(Modifiable), c.(Accessor).getDeclaration()] |
@@ -2072,12 +2128,12 @@ module Csv {
}
/** Gets a string representing whether the summary should apply for all overrides of `c`. */
private string getCallableOverride(DataFlowCallable c) {
private string getCallableOverride(DotNet::Callable c) {
if isBaseCallableOrPrototype(c) then result = "true" else result = "false"
}
/** Computes the first 6 columns for CSV rows of `c`. */
string asPartialModel(DataFlowCallable c) {
string asPartialModel(DotNet::Callable c) {
exists(string namespace, string type, string name |
c.getDeclaringType().hasQualifiedName(namespace, type) and
c.hasQualifiedName(_, name) and

View File

@@ -40,8 +40,8 @@ class Node extends TNode {
final DotNet::Type getType() { result = this.(NodeImpl).getTypeImpl() }
/** Gets the enclosing callable of this node. */
final DataFlowCallable getEnclosingCallable() {
result = this.(NodeImpl).getEnclosingCallableImpl()
final Callable getEnclosingCallable() {
result = this.(NodeImpl).getEnclosingCallableImpl().getUnderlyingCallable()
}
/** Gets the control flow node corresponding to this node, if any. */
@@ -103,7 +103,7 @@ class ParameterNode extends Node instanceof ParameterNodeImpl {
DotNet::Parameter getParameter() {
exists(DataFlowCallable c, ParameterPosition ppos |
super.isParameterOf(c, ppos) and
result = c.getParameter(ppos.getPosition())
result = c.getUnderlyingCallable().getParameter(ppos.getPosition())
)
}

View File

@@ -3,6 +3,7 @@
*/
private import csharp
private import dotnet
private import semmle.code.csharp.frameworks.system.linq.Expressions
private import DataFlowDispatch
private import DataFlowPrivate
@@ -12,6 +13,7 @@ private import FlowSummaryImpl::Private
private import FlowSummaryImpl::Public
private import semmle.code.csharp.Unification
private import semmle.code.csharp.dataflow.ExternalFlow
private import semmle.code.csharp.dataflow.FlowSummary as FlowSummary
/** Gets the parameter position of the instance parameter. */
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
@@ -36,7 +38,7 @@ DataFlowType getContentType(Content c) {
)
}
private DataFlowType getReturnTypeBase(DataFlowCallable c, ReturnKind rk) {
private DataFlowType getReturnTypeBase(DotNet::Callable c, ReturnKind rk) {
exists(Type t | result = Gvn::getGlobalValueNumber(t) |
rk instanceof NormalReturnKind and
(
@@ -53,7 +55,7 @@ private DataFlowType getReturnTypeBase(DataFlowCallable c, ReturnKind rk) {
/** Gets the return type of kind `rk` for callable `c`. */
bindingset[c]
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
result = getReturnTypeBase(c, rk)
result = getReturnTypeBase(c.asSummarizedCallable(), rk)
or
rk =
any(JumpReturnKind jrk | result = getReturnTypeBase(jrk.getTarget(), jrk.getTargetReturnKind()))
@@ -83,6 +85,21 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
)
}
private predicate summaryElement0(
DotNet::Callable c, string input, string output, string kind, boolean generated
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, generated) and
c = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
private class SummarizedCallableExternal extends FlowSummary::SummarizedCallable {
SummarizedCallableExternal() { summaryElement0(this, _, _, _, _) }
}
/**
* Holds if an external flow summary exists for `c` with input specification
* `input`, output specification `output`, kind `kind`, and a flag `generated`
@@ -91,12 +108,7 @@ DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
predicate summaryElement(
DataFlowCallable c, string input, string output, string kind, boolean generated
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, generated) and
c = interpretElement(namespace, type, subtypes, name, signature, ext)
)
summaryElement0(c.asSummarizedCallable(), input, output, kind, generated)
}
/**
@@ -219,10 +231,10 @@ class InterpretNode extends TInterpretNode {
DataFlowCall asCall() { this = TDataFlowCall_(result) }
/** Gets the callable that this node corresponds to, if any. */
DataFlowCallable asCallable() { result = this.asElement() }
DataFlowCallable asCallable() { result.getUnderlyingCallable() = this.asElement() }
/** Gets the target of this call, if any. */
Callable getCallTarget() { result = viableCallable(this.asCall()) }
Callable getCallTarget() { result = this.asCall().(NonDelegateDataFlowCall).getATarget(_) }
/** Gets a textual representation of this node. */
string toString() {

View File

@@ -568,7 +568,7 @@ class DelegateLikeCall extends Call, DelegateLikeCall_ {
final override Callable getARuntimeTarget() {
exists(ExplicitDelegateLikeDataFlowCall call |
this = call.getCall() and
result = viableCallableLambda(call, _)
result = viableCallableLambda(call, _).getUnderlyingCallable()
)
}

View File

@@ -1,6 +1,7 @@
/** Provides classes and predicates related to handling APIs from external libraries. */
private import csharp
private import dotnet
private import semmle.code.csharp.dispatch.Dispatch
private import semmle.code.csharp.dataflow.ExternalFlow
private import semmle.code.csharp.dataflow.FlowSummary
@@ -24,8 +25,8 @@ class TestLibrary extends RefType {
/**
* An external API from either the C# Standard Library or a 3rd party library.
*/
class ExternalApi extends DataFlowDispatch::DataFlowCallable {
ExternalApi() { this.fromLibrary() }
class ExternalApi extends DotNet::Callable {
ExternalApi() { this.isUnboundDeclaration() and this.fromLibrary() }
/**
* Gets the unbound type, name and parameter types of this API.
@@ -79,7 +80,8 @@ class ExternalApi extends DataFlowDispatch::DataFlowCallable {
/** Holds if this API has a supported summary. */
predicate hasSummary() {
this instanceof SummarizedCallable or
this instanceof SummarizedCallable
or
defaultAdditionalTaintStep(this.getAnInput(), _)
}

View File

@@ -3,6 +3,7 @@
*/
private import csharp as CS
private import dotnet
private import semmle.code.csharp.commons.Util as Util
private import semmle.code.csharp.commons.Collections as Collections
private import semmle.code.csharp.dataflow.internal.DataFlowDispatch
@@ -44,9 +45,10 @@ private predicate isRelevantForModels(CS::Callable api) {
* In the Standard library and 3rd party libraries it the callables that can be called
* from outside the library itself.
*/
class TargetApiSpecific extends DataFlowCallable {
class TargetApiSpecific extends DotNet::Callable {
TargetApiSpecific() {
this.fromSource() and
this.isUnboundDeclaration() and
isRelevantForModels(this)
}
}
@@ -110,7 +112,7 @@ string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
* Gets the enclosing callable of `ret`.
*/
CS::Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
result = DataFlowImplCommon::getNodeEnclosingCallable(ret)
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).getUnderlyingCallable()
}
/**

View File

@@ -17,7 +17,7 @@ class Conf extends DataFlow::Configuration {
)
}
override int fieldFlowBranchLimit() { result = 10 }
override int fieldFlowBranchLimit() { result = 100 }
}
from DataFlow::PathNode source, DataFlow::PathNode sink, Conf conf

View File

@@ -51,5 +51,5 @@ viableLambda
| DelegateFlow.cs:125:9:125:25 | function pointer call | file://:0:0:0:0 | (none) | DelegateFlow.cs:7:17:7:18 | M2 |
| DelegateFlow.cs:132:9:132:11 | delegate call | DelegateFlow.cs:135:25:135:40 | call to method M19 | DelegateFlow.cs:135:29:135:36 | (...) => ... |
| DelegateFlow.cs:132:9:132:11 | delegate call | file://:0:0:0:0 | (none) | DelegateFlow.cs:131:17:131:24 | (...) => ... |
| file://:0:0:0:0 | [summary] call to valueFactory in Lazy | DelegateFlow.cs:105:9:105:24 | object creation of type Lazy<Int32> | DelegateFlow.cs:104:23:104:30 | (...) => ... |
| file://:0:0:0:0 | [summary] call to valueFactory in Lazy | DelegateFlow.cs:107:9:107:24 | object creation of type Lazy<Int32> | DelegateFlow.cs:106:13:106:20 | (...) => ... |
| file://:0:0:0:0 | [summary] call to parameter position 0 of Lazy in Lazy | DelegateFlow.cs:105:9:105:24 | object creation of type Lazy<Int32> | DelegateFlow.cs:104:23:104:30 | (...) => ... |
| file://:0:0:0:0 | [summary] call to parameter position 0 of Lazy in Lazy | DelegateFlow.cs:107:9:107:24 | object creation of type Lazy<Int32> | DelegateFlow.cs:106:13:106:20 | (...) => ... |

View File

@@ -42,7 +42,9 @@ query predicate summarySetterStep(DataFlow::Node arg, DataFlow::Node out, Conten
FlowSummaryImpl::Private::Steps::summarySetterStep(arg, c, out)
}
query predicate clearsContent(SummarizedCallable c, DataFlow::Content k, ParameterPosition pos) {
query predicate clearsContent(
FlowSummaryImpl::Public::SummarizedCallable c, DataFlow::Content k, ParameterPosition pos
) {
c.clearsContent(pos, k) and
c.fromSource()
c.asSummarizedCallable().fromSource()
}

View File

@@ -1,5 +1,5 @@
import shared.FlowSummaries
private class IncludeAllSummarizedCallable extends IncludeSummarizedCallable {
IncludeAllSummarizedCallable() { this instanceof SummarizedCallable }
IncludeAllSummarizedCallable() { exists(this) }
}

View File

@@ -3,7 +3,7 @@ private import semmle.code.csharp.dataflow.internal.DataFlowPrivate::Csv
private import semmle.code.csharp.dataflow.ExternalFlow
class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
IncludeFilteredSummarizedCallable() { this instanceof SummarizedCallable }
IncludeFilteredSummarizedCallable() { exists(this) }
/**
* Holds if flow is propagated between `input` and `output` and
@@ -14,10 +14,11 @@ class IncludeFilteredSummarizedCallable extends IncludeSummarizedCallable {
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
this.propagatesFlow(input, output, preservesValue) and
not exists(IncludeSummarizedCallable rsc |
isBaseCallableOrPrototype(rsc) and
not exists(IncludeSummarizedCallable rsc, SummarizedCallable sc |
sc = rsc.asSummarizedCallable() and
isBaseCallableOrPrototype(sc) and
rsc.propagatesFlow(input, output, preservesValue) and
this.(UnboundCallable).overridesOrImplementsUnbound(rsc)
this.asSummarizedCallable().(UnboundCallable).overridesOrImplementsUnbound(sc)
)
}
}

View File

@@ -3,7 +3,7 @@ import shared.FlowSummaries
import semmle.code.csharp.dataflow.ExternalFlow as ExternalFlow
private class IncludeEFSummarizedCallable extends IncludeSummarizedCallable {
IncludeEFSummarizedCallable() { this instanceof EFSummarizedCallable }
IncludeEFSummarizedCallable() { this.asSummarizedCallable() instanceof EFSummarizedCallable }
}
query predicate sourceNode(DataFlow::Node node, string kind) {

View File

@@ -4,9 +4,12 @@ private import semmle.code.csharp.dataflow.internal.DataFlowPrivate
abstract class IncludeSummarizedCallable extends RelevantSummarizedCallable {
IncludeSummarizedCallable() {
[this.(Modifiable), this.(Accessor).getDeclaration()].isEffectivelyPublic()
this.asSummarizedCallable() =
any(Callable c | [c.(Modifiable), c.(Accessor).getDeclaration()].isEffectivelyPublic())
}
/** Gets a string representing the callable in semi-colon separated format for use in flow summaries. */
final override string getCallableCsv() { result = Csv::asPartialModel(this) }
final override string getCallableCsv() {
result = Csv::asPartialModel(this.asSummarizedCallable())
}
}