Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 3 additions & 6 deletions cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@
import cpp
private import new.DataFlow
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as Nodes
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import internal.FlowSummaryImpl
Expand Down Expand Up @@ -952,9 +953,7 @@ private module Cached {
*/
cached
predicate sourceNode(DataFlow::Node node, string kind, string model) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSourceNode(n, kind, model) and n.asNode() = node
)
node.(Nodes::FlowSummaryNode).isSource(kind, model)
}

/**
Expand All @@ -963,9 +962,7 @@ private module Cached {
*/
cached
predicate sinkNode(DataFlow::Node node, string kind, string model) {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSinkNode(n, kind, model) and n.asNode() = node
)
node.(Nodes::FlowSummaryNode).isSink(kind, model)
}

private newtype TKindModelPair =
Expand Down
157 changes: 149 additions & 8 deletions cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {

class SummarizedCallableBase = Function;

class SourceBase extends Void {
Location getLocation() { none() }
}
class SourceBase = Function;

class SinkBase = SourceBase;
class SinkBase = Function;

class FlowSummaryCallBase = CallInstruction;

Expand Down Expand Up @@ -134,15 +132,120 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {

private import Make<Location, DataFlowImplSpecific::CppDataFlow, Input> as Impl

private class ConversionCall extends Call {
ConversionCall() { this.getTarget() instanceof ConversionOperator }
}

private module Input2 implements Impl::Private::InputSig2 {
private import codeql.util.Void

class SourceSinkReportingElement extends Void {
Location getLocation() { none() }
class SourceSinkReportingElement extends Element {
SourceSinkReportingElement() { this instanceof Expr or this instanceof Parameter }

DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() =
[this.(Expr).getEnclosingFunction(), this.(Parameter).getFunction()]
}

/**
* Gets the member function corresponding to an overloaded `operator()` when this element is
* invoked.
*/
private MemberFunction getOperatorCallFunction() {
// An `operator()` on a struct
result.getClassAndName("operator()").getADerivedClass*() = this.(Expr).getUnspecifiedType()
or
// A lambda that has undergone "lambda to function-pointer conversion"
result = this.(ConversionCall).getQualifier().(LambdaExpression).getLambdaFunction()
}

SourceSinkReportingElement getASuccessor(Impl::Private::SummaryComponent sc) {
exists(ParameterPosition pos | sc = Impl::Private::SummaryComponent::parameter(pos) |
// Taking the address of a function
result = pos.getParameter(this.(FunctionAccess).getTarget())
or
// Passing an object with an overloaded `operator()`
result = pos.getParameter(this.getOperatorCallFunction())
)
}
}

bindingset[source, sc]
SourceSinkReportingElement getASourceReportingElement(
Input::SourceBase source, Impl::Private::SummaryComponent sc
) {
exists(Call call | call.getTarget() = source |
sc = Impl::Private::SummaryComponent::return(_) and
result = call
or
exists(ArgumentPosition pos |
sc = Impl::Private::SummaryComponent::argument(pos) and
result = pos.getArgument(call)
)
)
or
exists(ParameterPosition pos |
sc = Impl::Private::SummaryComponent::parameter(pos) and
result = pos.getParameter(source)
)
}

pragma[nomagic]
private IndirectReturnOutNode getIndirectReturn(CallInstruction call, NormalReturnKind rk) {
result.getCallInstruction() = call and
pragma[only_bind_out](result.getIndirectionIndex()) =
pragma[only_bind_out](rk.getIndirectionIndex())
}

bindingset[e, sc]
Node getSourceDataFlowNode(SourceSinkReportingElement e, Impl::Private::SummaryComponent sc) {
exists(DataFlowCall call |
exists(ArgumentPosition pos |
sc = Impl::Private::SummaryComponent::argument(pos) and
pos.getArgument(call.asCallInstruction().getUnconvertedResultExpression()) = e
|
pos.getIndirectionIndex() = 0 and
result.(PostUpdateNode).getPreUpdateNode().asExpr() = e
or
result.(PostUpdateNode).getPreUpdateNode().asIndirectExpr(pos.getIndirectionIndex()) = e
)
or
exists(ReturnKind rk |
sc = Impl::Private::SummaryComponent::return(rk) and
e = call.asCallInstruction().getUnconvertedResultExpression()
|
rk.getIndirectionIndex() = 0 and
simpleOutNode(result, call.asCallInstruction())
or
result = getIndirectReturn(call.asCallInstruction(), rk)
)
)
or
exists(ParameterPosition pos, ParameterNode p |
sc = Impl::Private::SummaryComponent::parameter(pos) and
p.isParameterOf(e.getEnclosingCallable(), pos) and
result = p
)
}

DataFlowCallable getEnclosingCallable() { none() }
bindingset[sink, sc]
SourceSinkReportingElement getASinkReportingElement(
Input::SinkBase sink, Impl::Private::SummaryComponent sc
) {
exists(Call call, ArgumentPosition pos |
call.getTarget() = sink and
sc = Impl::Private::SummaryComponent::argument(pos) and
result = pos.getArgument(call)
)
}

SourceSinkReportingElement getASuccessor(Impl::Private::SummaryComponent sc) { none() }
bindingset[e, sc]
Node getSinkDataFlowNode(SourceSinkReportingElement e, Impl::Private::SummaryComponent sc) {
exists(ArgumentPosition pos, CallInstruction call |
sc = Impl::Private::SummaryComponent::argument(pos) and
pos.getArgument(call.getUnconvertedResultExpression()) = e and
result.(ArgumentNode).sourceArgumentOf(call, pos)
)
}
}

Expand Down Expand Up @@ -319,3 +422,41 @@ module Private {
}

module Public = Impl::Public;

private class SourceModelFunction extends Public::SourceElement instanceof Function {
private string namespace;
private string type;
private boolean subtypes;
private string name;
private string signature;
private string ext;

SourceModelFunction() {
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) and
this = interpretElement(namespace, type, subtypes, name, signature, ext)
}

override predicate isSource(
string output, string kind, Public::Provenance provenance, string model
) {
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model)
}
}

private class SinkModelFunction extends Public::SinkElement instanceof Function {
private string namespace;
private string type;
private boolean subtypes;
private string name;
private string signature;
private string ext;

SinkModelFunction() {
sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) and
this = interpretElement(namespace, type, subtypes, name, signature, ext)
}

override predicate isSink(string input, string kind, Public::Provenance provenance, string model) {
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance, model)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
private import cpp
private import DataFlowImplSpecific
private import TaintTrackingImplSpecific
private import DataFlowNodes as Nodes
private import semmle.code.cpp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
private import codeql.dataflow.internal.DataFlowImplConsistency

private module Input implements InputSig<Location, CppDataFlow> {
Expand All @@ -14,6 +16,12 @@ private module Input implements InputSig<Location, CppDataFlow> {
// complex to model here.
any()
}

predicate postWithInFlowExclude(CppDataFlow::Node n) {
n instanceof Nodes::FlowSummaryNode
or
FlowSummaryImpl::Private::Steps::summaryLocalStep(_, n, _, _)
}
}

module Consistency = MakeConsistency<Location, CppDataFlow, CppTaintTracking, Input>;
Original file line number Diff line number Diff line change
Expand Up @@ -1541,6 +1541,42 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
override Location getLocationImpl() { result = this.getSummaryNode().getLocation() }

override string toStringImpl() { result = this.getSummaryNode().toString() }

/** Gets the source element that this node belongs to, if any. */
FlowSummaryImpl::Public::SourceElement getSourceElement() {
result = this.getSummaryNode().getSourceElement()
}

/** Gets the sink element that this node belongs to, if any. */
FlowSummaryImpl::Public::SinkElement getSinkElement() {
result = this.getSummaryNode().getSinkElement()
}

/** Holds if this node is a source node of kind `kind`. */
predicate isSource(string kind, string model) {
this.getSummaryNode().(FlowSummaryImpl::Private::SourceOutputNode).isEntry(kind, model)
}

/** Holds if this node is a sink node of kind `kind`. */
predicate isSink(string kind, string model) {
this.getSummaryNode().(FlowSummaryImpl::Private::SinkInputNode).isExit(kind, model)
}
}

private class SourceOutputNode extends FlowSummaryImpl::Private::SourceOutputNode {
final override string toString() {
exists(Call call |
this.isOutArgument(call) and
result = call.getTarget() + " output argument"
)
or
not this.isOutArgument(_) and
result = super.toString()
}

private predicate isOutArgument(Call call) {
[call.getAnArgument(), call.getQualifier()] = this.getSourceSinkReportingElement()
}
}

/**
Expand Down Expand Up @@ -1655,13 +1691,13 @@ abstract private class AbstractParameterNode extends Node {
* Holds if this node represents an implicit `this` parameter, if it exists.
*/
predicate isThis() { none() } // overridden by subclasses
}

abstract private class AbstractIndirectParameterNode extends AbstractParameterNode {
/** Gets the indirection index of this parameter node. */
abstract int getIndirectionIndex();
int getIndirectionIndex() { none() }
}

abstract private class AbstractIndirectParameterNode extends AbstractParameterNode { }

pragma[noinline]
private predicate indirectParameterNodeHasArgumentIndexAndIndex(
IndirectInstructionParameterNode node, int argumentIndex, int indirectionIndex
Expand Down Expand Up @@ -1725,7 +1761,9 @@ private class IndirectInstructionParameterNode extends AbstractIndirectParameter
final override int getIndirectionIndex() { this.hasInstructionAndIndirectionIndex(init, result) }
}

abstract private class AbstractDirectParameterNode extends AbstractParameterNode { }
abstract private class AbstractDirectParameterNode extends AbstractParameterNode {
override int getIndirectionIndex() { result = 0 }
}

/**
* A non-indirect parameter node that is represented as an `Instruction`.
Expand Down Expand Up @@ -1796,6 +1834,8 @@ private class DirectBodyLessParameterNode extends AbstractExplicitParameterNode,
}

override Parameter getParameter() { result = p }

final override int getIndirectionIndex() { result = 0 }
}

private class IndirectBodyLessParameterNode extends AbstractIndirectParameterNode,
Expand Down
Loading
Loading