mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
Merge pull request #9014 from michaelnebel/csharp/dataflowcallablerefactor
C#: Dataflow callable refactoring.
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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())
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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(), _)
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 | (...) => ... |
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import shared.FlowSummaries
|
||||
|
||||
private class IncludeAllSummarizedCallable extends IncludeSummarizedCallable {
|
||||
IncludeAllSummarizedCallable() { this instanceof SummarizedCallable }
|
||||
IncludeAllSummarizedCallable() { exists(this) }
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user