Skip to content

Commit

Permalink
C#
Browse files Browse the repository at this point in the history
  • Loading branch information
hvitved committed Oct 24, 2023
1 parent 5f1bf3d commit 6185feb
Show file tree
Hide file tree
Showing 16 changed files with 424 additions and 15,975 deletions.
1 change: 0 additions & 1 deletion config/identical-files.json
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,6 @@
"ruby/ql/lib/codeql/ruby/typetracking/internal/SummaryTypeTracker.qll"
],
"AccessPathSyntax": [
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll",
"go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll",
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/AccessPathSyntax.qll",
Expand Down
57 changes: 51 additions & 6 deletions csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@

import csharp
private import ExternalFlowExtensions as Extensions
private import internal.AccessPathSyntax
private import internal.DataFlowDispatch
private import internal.DataFlowPrivate
private import internal.DataFlowPublic
private import internal.FlowSummaryImpl
private import internal.FlowSummaryImpl::Public
private import internal.FlowSummaryImpl::Private
private import internal.FlowSummaryImpl::Private::External
private import internal.FlowSummaryImplSpecific
private import codeql.mad.ModelValidation as SharedModelVal

/** Holds if a source model exists for the given parameters. */
Expand Down Expand Up @@ -422,14 +422,14 @@ Element interpretElement(
* A callable where there exists a MaD sink model that applies to it.
*/
class SinkCallable extends Callable {
SinkCallable() { sinkElement(this, _, _, _) }
SinkCallable() { SourceSinkInterpretationInput::sinkElement(this, _, _, _) }
}

/**
* A callable where there exists a MaD source model that applies to it.
*/
class SourceCallable extends Callable {
SourceCallable() { sourceElement(this, _, _, _) }
SourceCallable() { SourceSinkInterpretationInput::sourceElement(this, _, _, _) }
}

cached
Expand All @@ -440,7 +440,9 @@ private module Cached {
*/
cached
predicate sourceNode(Node node, string kind) {
exists(InterpretNode n | isSourceNode(n, kind) and n.asNode() = node)
exists(SourceSinkInterpretationInput::InterpretNode n |
isSourceNode(n, kind) and n.asNode() = node
)
}

/**
Expand All @@ -449,8 +451,51 @@ private module Cached {
*/
cached
predicate sinkNode(Node node, string kind) {
exists(InterpretNode n | isSinkNode(n, kind) and n.asNode() = node)
exists(SourceSinkInterpretationInput::InterpretNode n |
isSinkNode(n, kind) and n.asNode() = node
)
}
}

import Cached

private class SummarizedCallableAdapter extends SummarizedCallable {
string input_;
string output_;
string kind;
string provenance_;

SummarizedCallableAdapter() {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, input_, output_, kind,
provenance_) and
this = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}

override predicate propagatesFlow(string input, string output, boolean preservesValue) {
input = input_ and
output = output_ and
if kind = "value" then preservesValue = true else preservesValue = false
}

override predicate hasProvenance(Provenance provenance) { provenance = provenance_ }
}

private class NeutralCallableAdapter extends NeutralCallable {
string kind;
string provenance_;

NeutralCallableAdapter() {
exists(string namespace, string type, string name, string signature |
neutralModel(namespace, type, name, signature, kind, provenance_) and
this = interpretElement(namespace, type, false, name, signature, "")
)
}

override string getKind() { result = kind }

override predicate hasProvenance(Provenance provenance) { provenance = provenance_ }
}
189 changes: 7 additions & 182 deletions csharp/ql/lib/semmle/code/csharp/dataflow/FlowSummary.qll
Original file line number Diff line number Diff line change
@@ -1,198 +1,23 @@
/** 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
private import Impl::Public::SummaryComponent as SummaryComponentInternal

class ParameterPosition = DataFlowDispatch::ParameterPosition;
deprecated class ParameterPosition = DataFlowDispatch::ParameterPosition;

class ArgumentPosition = DataFlowDispatch::ArgumentPosition;
deprecated class ArgumentPosition = DataFlowDispatch::ArgumentPosition;

// import all instances below
private module Summaries {
private import semmle.code.csharp.frameworks.EntityFramework
}
deprecated class SummaryComponent = Impl::Private::SummaryComponent;

class SummaryComponent = Impl::Public::SummaryComponent;
deprecated module SummaryComponent = Impl::Private::SummaryComponent;

/** Provides predicates for constructing summary components. */
module SummaryComponent {
predicate content = SummaryComponentInternal::content/1;
deprecated class SummaryComponentStack = Impl::Private::SummaryComponentStack;

/** Gets a summary component for parameter `i`. */
SummaryComponent parameter(int i) {
exists(ArgumentPosition pos |
result = SummaryComponentInternal::parameter(pos) and
i = pos.getPosition()
)
}
deprecated module SummaryComponentStack = Impl::Private::SummaryComponentStack;

/** Gets a summary component for argument `i`. */
SummaryComponent argument(int i) {
exists(ParameterPosition pos |
result = SummaryComponentInternal::argument(pos) and
i = pos.getPosition()
)
}

predicate return = SummaryComponentInternal::return/1;

/** Gets a summary component that represents a qualifier. */
SummaryComponent qualifier() {
exists(ParameterPosition pos |
result = SummaryComponentInternal::argument(pos) and
pos.isThisParameter()
)
}

/** Gets a summary component that represents an element in a collection. */
SummaryComponent element() { result = content(any(DataFlow::ElementContent c)) }

/** Gets a summary component for property `p`. */
SummaryComponent property(Property p) {
result = content(any(DataFlow::PropertyContent c | c.getProperty() = p.getUnboundDeclaration()))
}

/** Gets a summary component for field `f`. */
SummaryComponent field(Field f) {
result = content(any(DataFlow::FieldContent c | c.getField() = f.getUnboundDeclaration()))
}

/** Gets a summary component that represents the return value of a call. */
SummaryComponent return() { result = return(any(DataFlowDispatch::NormalReturnKind rk)) }

predicate syntheticGlobal = SummaryComponentInternal::syntheticGlobal/1;

class SyntheticGlobal = SummaryComponentInternal::SyntheticGlobal;
}

class SummaryComponentStack = Impl::Public::SummaryComponentStack;

/** Provides predicates for constructing stacks of summary components. */
module SummaryComponentStack {
private import Impl::Public::SummaryComponentStack as SummaryComponentStackInternal

predicate singleton = SummaryComponentStackInternal::singleton/1;

predicate push = SummaryComponentStackInternal::push/2;

/** Gets a singleton stack for argument `i`. */
SummaryComponentStack argument(int i) { result = singleton(SummaryComponent::argument(i)) }

predicate return = SummaryComponentStackInternal::return/1;

/** Gets a singleton stack representing a qualifier. */
SummaryComponentStack qualifier() { result = singleton(SummaryComponent::qualifier()) }

/** Gets a stack representing an element of `container`. */
SummaryComponentStack elementOf(SummaryComponentStack container) {
result = push(SummaryComponent::element(), container)
}

/** Gets a stack representing a property `p` of `object`. */
SummaryComponentStack propertyOf(Property p, SummaryComponentStack object) {
result = push(SummaryComponent::property(p), object)
}

/** Gets a stack representing a field `f` of `object`. */
SummaryComponentStack fieldOf(Field f, SummaryComponentStack object) {
result = push(SummaryComponent::field(f), object)
}

/** Gets a singleton stack representing the return value of a call. */
SummaryComponentStack return() { result = singleton(SummaryComponent::return()) }

/** Gets a singleton stack representing a synthetic global with name `name`. */
SummaryComponentStack syntheticGlobal(string synthetic) {
result = singleton(SummaryComponent::syntheticGlobal(synthetic))
}

/**
* DEPRECATED: Use the member predicate `getMadRepresentation` instead.
*
* Gets a textual representation of this stack used for flow summaries.
*/
deprecated string getComponentStack(SummaryComponentStack s) { result = s.getMadRepresentation() }
}
deprecated class RequiredSummaryComponentStack = Impl::Private::RequiredSummaryComponentStack;

class SummarizedCallable = Impl::Public::SummarizedCallable;

private predicate recordConstructorFlow(Constructor c, int i, Property p) {
c = any(RecordType r).getAMember() and
exists(string name |
c.getParameter(i).getName() = name and
c.getDeclaringType().getAMember(name) = p
)
}

private class RecordConstructorFlow extends SummarizedCallable {
RecordConstructorFlow() { recordConstructorFlow(this, _, _) }

override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
exists(int i, Property p |
recordConstructorFlow(this, i, p) and
input = SummaryComponentStack::argument(i) and
output = SummaryComponentStack::propertyOf(p, SummaryComponentStack::return()) and
preservesValue = true
)
}
}

class RequiredSummaryComponentStack = Impl::Public::RequiredSummaryComponentStack;

private class RecordConstructorFlowRequiredSummaryComponentStack extends RequiredSummaryComponentStack
{
override predicate required(SummaryComponent head, SummaryComponentStack tail) {
exists(Property p |
recordConstructorFlow(_, _, p) and
head = SummaryComponent::property(p) and
tail = SummaryComponentStack::return()
)
}
}

class Provenance = Impl::Public::Provenance;

private import semmle.code.csharp.frameworks.system.linq.Expressions

private SummaryComponent delegateSelf() {
exists(ArgumentPosition pos |
result = SummaryComponentInternal::parameter(pos) and
pos.isDelegateSelf()
)
}

private predicate mayInvokeCallback(Callable c, int n) {
c.getParameter(n).getType() instanceof SystemLinqExpressions::DelegateExtType and
not c.fromSource()
}

private class SummarizedCallableWithCallback extends SummarizedCallable {
private int pos;

SummarizedCallableWithCallback() { mayInvokeCallback(this, pos) }

override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
input = SummaryComponentStack::argument(pos) and
output = SummaryComponentStack::push(delegateSelf(), input) and
preservesValue = true
}

override predicate hasProvenance(Provenance provenance) { provenance = "hq-generated" }
}

private class RequiredComponentStackForCallback extends RequiredSummaryComponentStack {
override predicate required(SummaryComponent head, SummaryComponentStack tail) {
exists(int pos |
mayInvokeCallback(_, pos) and
head = delegateSelf() and
tail = SummaryComponentStack::argument(pos)
)
}
}
Loading

0 comments on commit 6185feb

Please sign in to comment.