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
3 changes: 3 additions & 0 deletions cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ private import new.DataFlow
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as Nodes
private import internal.FlowSummaryImpl
private import internal.FlowSummaryImpl::Public
private import internal.FlowSummaryImpl::Private
Expand Down Expand Up @@ -955,6 +956,8 @@ private module Cached {
exists(SourceSinkInterpretationInput::InterpretNode n |
isSourceNode(n, kind, model) and n.asNode() = node
)
or
node.(Nodes::FlowSummaryNode).isSource(kind, model)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,32 @@
private import semmle.code.cpp.ir.IR

module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
private import codeql.util.Void

class SummarizedCallableBase = Function;

class SourceBase = Void;
abstract private class SourceSinkBase extends Element {
/** Gets the call associated with this element, if any. */
CallInstruction getCall() { none() }

/** Gets the function associated with this element, if any. */
Function getFunction() { none() }

/** Gets the enclosing function of this element. */
abstract Declaration getEnclosingFunction();
}

abstract class SourceBase extends SourceSinkBase { }

abstract class SinkBase extends SourceSinkBase { }

private class SourceSinkCall extends SourceBase, SinkBase instanceof Call {
CallInstruction call;

SourceSinkCall() { call.getUnconvertedResultExpression() = this }

class SinkBase = Void;
final override CallInstruction getCall() { result = call }

final override Declaration getEnclosingFunction() { result = Call.super.getEnclosingFunction() }
}

class FlowSummaryCallBase = CallInstruction;

Expand Down Expand Up @@ -149,9 +168,46 @@
)
}

DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() }
DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) {
result.asSourceCallable() = source.getEnclosingFunction()
}

private ArgumentNode getSourceNodeArgument(
Input::SourceBase source, Impl::Private::SummaryComponent sc
) {
exists(Position pos, DataFlowCall call |
sc = Impl::Private::SummaryComponent::argument(pos) and
source.getCall() = call.asCallInstruction() and
result.argumentOf(call, pos)
)
}

Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() }
Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) {
exists(ReturnKind rk, DataFlowCall call |
s.head() = Impl::Private::SummaryComponent::return(rk) and
source.getCall() = call.asCallInstruction() and
result = getAnOutNode(call, rk)
)
or
exists(Position pos, DataFlowCallable callable |
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
result.(ParameterNode).isParameterOf(callable, pos)
|
exists(ArgumentNode arg, DataFlowCall call |
arg = getSourceNodeArgument(source, s.tail().headOfSingleton()) and
arg.argumentOf(call, pos) and
callable = call.getStaticCallTarget()
)
or
source.getFunction() = callable.asSourceCallable()
)
or
exists(Position pos |

Check warning

Code scanning / CodeQL

Omittable 'exists' variable Warning

This exists variable can be omitted by using a don't-care expression
in this argument
.
s.head() = Impl::Private::SummaryComponent::argument(pos) and
result.(PostUpdateNode).getPreUpdateNode() =
getSourceNodeArgument(source, s.headOfSingleton())
)
}

Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
}
Expand Down Expand Up @@ -310,3 +366,26 @@
}

module Public = Impl::Public;

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

SourceModelCall() {
exists(string output |
sourceModel(namespace, type, subtypes, name, signature, ext, output, _, _, _) and
output.matches("%" + Input::encodeContent(_, _) + "%")
) and
this.getTarget() = 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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1534,11 +1534,46 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
result = this.getSummaryNode().getSummarizedCallable()
}

/** 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)
}

/**
* Gets the enclosing callable. For a `FlowSummaryNode` this is always the
* summarized function this node is part of.
*/
override DataFlowCallable getEnclosingCallable() {
result = FlowSummaryImpl::Private::getEnclosingCallable(this.getSummaryNode())
or
// TODO: This could actually be done by the shared library.
result.asSourceCallable() = this.getSourceElement().getEnclosingFunction()
or
result.asSourceCallable() = this.getSinkElement().getEnclosingFunction()
}

override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
override Location getLocationImpl() {
result = this.getSummarizedCallable().getLocation()
or
result = this.getSourceElement().getLocation()
or
result = this.getSinkElement().getLocation()
}

override string toStringImpl() { result = this.getSummaryNode().toString() }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ private module Cached {
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
n2.(FlowSummaryNode).getSummaryNode())
or
FlowSummaryImpl::Private::Steps::sourceJumpStep(n1.(FlowSummaryNode).getSummaryNode(), n2)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ private module Cached {
// models-as-data summarized flow
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
or
FlowSummaryImpl::Private::Steps::sourceLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
nodeTo, model)
or
FlowSummaryImpl::Private::Steps::sinkLocalStep(nodeFrom,
nodeTo.(FlowSummaryNode).getSummaryNode(), model)
}

private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) {
Expand Down
Loading
Loading