mirror of
https://github.com/github/codeql.git
synced 2025-12-22 11:46:32 +01:00
249 lines
7.6 KiB
Plaintext
249 lines
7.6 KiB
Plaintext
/**
|
|
* Provides classes and predicates for defining flow summaries.
|
|
*/
|
|
|
|
private import cpp
|
|
private import codeql.dataflow.internal.FlowSummaryImpl
|
|
private import codeql.dataflow.internal.AccessPathSyntax as AccessPath
|
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate
|
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
|
|
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplSpecific as DataFlowImplSpecific
|
|
private import semmle.code.cpp.dataflow.ExternalFlow
|
|
|
|
module Input implements InputSig<DataFlowImplSpecific::CppDataFlow> {
|
|
class SummarizedCallableBase = Function;
|
|
|
|
ArgumentPosition callbackSelfParameterPosition() { result = TDirectPosition(-1) }
|
|
|
|
ReturnKind getStandardReturnValueKind() { result.(NormalReturnKind).getIndirectionIndex() = 0 }
|
|
|
|
string encodeParameterPosition(ParameterPosition pos) { result = pos.toString() }
|
|
|
|
string encodeArgumentPosition(ArgumentPosition pos) { result = pos.toString() }
|
|
|
|
string encodeReturn(ReturnKind rk, string arg) {
|
|
rk != getStandardReturnValueKind() and
|
|
result = "ReturnValue" and
|
|
arg = rk.toString()
|
|
}
|
|
|
|
string encodeContent(ContentSet cs, string arg) {
|
|
exists(FieldContent c |
|
|
cs.isSingleton(c) and
|
|
result = "Field" and
|
|
arg = c.getField().getName()
|
|
)
|
|
/*
|
|
* or
|
|
* exists(Content::TupleContent c |
|
|
* cs.isSingleton(c) and
|
|
* result = "TupleElement" and
|
|
* arg = c.getIndex().toString()
|
|
* )
|
|
* or
|
|
* exists(Content::EnumContent c, string sig |
|
|
* cs.isSingleton(c) and
|
|
* sig = c.getSignature()
|
|
* |
|
|
* if sig = "some:0"
|
|
* then
|
|
* result = "OptionalSome" and
|
|
* arg = ""
|
|
* else (
|
|
* result = "EnumElement" and
|
|
* arg = sig
|
|
* )
|
|
* )
|
|
* or
|
|
* exists(Content::CollectionContent c |
|
|
* cs.isSingleton(c) and
|
|
* result = "CollectionElement" and
|
|
* arg = ""
|
|
* )
|
|
*/
|
|
|
|
}
|
|
|
|
string encodeWithoutContent(ContentSet c, string arg) {
|
|
result = "WithoutContent" + c and arg = ""
|
|
}
|
|
|
|
string encodeWithContent(ContentSet c, string arg) { result = "WithContent" + c and arg = "" }
|
|
|
|
bindingset[token]
|
|
ParameterPosition decodeUnknownParameterPosition(AccessPath::AccessPathTokenBase token) {
|
|
// needed to support `Argument[x..y]` ranges and `Argument[-1]`
|
|
token.getName() = "Argument" and
|
|
exists(int pos | pos = AccessPath::parseInt(token.getAnArgument()) |
|
|
result = TDirectPosition(pos)
|
|
)
|
|
}
|
|
|
|
bindingset[token]
|
|
ArgumentPosition decodeUnknownArgumentPosition(AccessPath::AccessPathTokenBase token) {
|
|
// needed to support `Parameter[x..y]` ranges and `Parameter[-1]`
|
|
token.getName() = "Parameter" and
|
|
exists(int pos | pos = AccessPath::parseInt(token.getAnArgument()) |
|
|
result = TDirectPosition(pos)
|
|
)
|
|
}
|
|
}
|
|
|
|
/*private*/ import Make<DataFlowImplSpecific::CppDataFlow, Input> as Impl
|
|
|
|
private module StepsInput implements Impl::Private::StepsInputSig {
|
|
DataFlowCall getACall(Public::SummarizedCallable sc) { result.getStaticCallTarget() = sc }
|
|
}
|
|
|
|
module SourceSinkInterpretationInput implements
|
|
Impl::Private::External::SourceSinkInterpretationInputSig<Location>
|
|
{
|
|
class Element = Element;
|
|
|
|
class SourceOrSinkElement = Element;
|
|
|
|
/**
|
|
* Holds if an external source specification exists for `e` with output specification
|
|
* `output`, kind `kind`, and provenance `provenance`.
|
|
*/
|
|
predicate sourceElement(SourceOrSinkElement e, string output, string kind) {
|
|
exists(
|
|
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
|
|
|
|
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, _) and
|
|
e = interpretElement(namespace, type, subtypes, name, signature, ext)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Holds if an external sink specification exists for `e` with input specification
|
|
* `input`, kind `kind` and provenance `provenance`.
|
|
*/
|
|
predicate sinkElement(SourceOrSinkElement e, string input, string kind) {
|
|
exists(
|
|
string package, string type, boolean subtypes, string name, string signature, string ext
|
|
|
|
|
sinkModel(package, type, subtypes, name, signature, ext, input, kind, _) and
|
|
e = interpretElement(package, type, subtypes, name, signature, ext)
|
|
)
|
|
}
|
|
|
|
private newtype TInterpretNode =
|
|
TElement_(Element n) or
|
|
TNode_(Node n) or
|
|
TDataFlowCall_(DataFlowCall c)
|
|
|
|
/** An entity used to interpret a source/sink specification. */
|
|
class InterpretNode extends TInterpretNode {
|
|
/** Gets the element that this node corresponds to, if any. */
|
|
SourceOrSinkElement asElement() { this = TElement_(result) }
|
|
|
|
/** Gets the data-flow node that this node corresponds to, if any. */
|
|
Node asNode() { this = TNode_(result) }
|
|
|
|
/** Gets the call that this node corresponds to, if any. */
|
|
DataFlowCall asCall() { this = TDataFlowCall_(result) }
|
|
|
|
/** Gets the callable that this node corresponds to, if any. */
|
|
DataFlowCallable asCallable() { result.(Function) = this.asElement() }
|
|
|
|
/** Gets the target of this call, if any. */
|
|
Element getCallTarget() {
|
|
result = this.asNode().asExpr().(Call).getTarget()
|
|
}
|
|
|
|
/** Gets a textual representation of this node. */
|
|
string toString() {
|
|
result = this.asElement().toString()
|
|
or
|
|
result = this.asNode().toString()
|
|
or
|
|
result = this.asCall().toString()
|
|
}
|
|
|
|
/** Gets the location of this node. */
|
|
Location getLocation() {
|
|
result = this.asElement().getLocation()
|
|
or
|
|
result = this.asNode().getLocation()
|
|
or
|
|
result = this.asCall().getLocation()
|
|
}
|
|
}
|
|
|
|
/** Provides additional sink specification logic. */
|
|
bindingset[c]
|
|
predicate interpretOutput(string c, InterpretNode mid, InterpretNode node) {
|
|
// Allow fields to be picked as output nodes.
|
|
exists(Node n, Element ast |
|
|
n = node.asNode() and
|
|
ast = mid.asElement()
|
|
|
|
|
c = "" and
|
|
n.asExpr().(VariableAccess).getTarget() = ast
|
|
)
|
|
}
|
|
|
|
/** Provides additional source specification logic. */
|
|
bindingset[c]
|
|
predicate interpretInput(string c, InterpretNode mid, InterpretNode node) {
|
|
exists(Node n, Element ast, VariableAccess e |
|
|
n = node.asNode() and
|
|
ast = mid.asElement() and
|
|
e.getTarget() = ast
|
|
|
|
|
// Allow fields to be picked as input nodes.
|
|
c = "" and
|
|
e.getQualifier() = n.asExpr()
|
|
or
|
|
// Allow post update nodes to be picked as input nodes when the `input` column
|
|
// of the row is `PostUpdate`.
|
|
c = "PostUpdate" and
|
|
e.getQualifier() = n.(PostUpdateNode).getPreUpdateNode().asExpr()
|
|
)
|
|
}
|
|
}
|
|
|
|
module Private {
|
|
import Impl::Private
|
|
|
|
module Steps = Impl::Private::Steps<StepsInput>;
|
|
|
|
module External {
|
|
import Impl::Private::External
|
|
import Impl::Private::External::SourceSinkInterpretation<Location, SourceSinkInterpretationInput>
|
|
}
|
|
|
|
/**
|
|
* Provides predicates for constructing summary components.
|
|
*/
|
|
module SummaryComponent {
|
|
private import Impl::Private::SummaryComponent as SC
|
|
|
|
predicate parameter = SC::parameter/1;
|
|
|
|
predicate argument = SC::argument/1;
|
|
|
|
predicate content = SC::content/1;
|
|
|
|
predicate withoutContent = SC::withoutContent/1;
|
|
|
|
predicate withContent = SC::withContent/1;
|
|
}
|
|
|
|
/**
|
|
* Provides predicates for constructing stacks of summary components.
|
|
*/
|
|
module SummaryComponentStack {
|
|
private import Impl::Private::SummaryComponentStack as SCS
|
|
|
|
predicate singleton = SCS::singleton/1;
|
|
|
|
predicate push = SCS::push/2;
|
|
|
|
predicate argument = SCS::argument/1;
|
|
}
|
|
}
|
|
|
|
module Public = Impl::Public;
|