Skip to content
Draft

TEMP PR #22137

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
5 changes: 2 additions & 3 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 @@ -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 Down
129 changes: 115 additions & 14 deletions cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ private import semmle.code.cpp.dataflow.ExternalFlow
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;
class SourceBase = Function;

class SinkBase = Void;
class SinkBase = Function;

class FlowSummaryCallBase = CallInstruction;

Expand Down Expand Up @@ -132,11 +130,99 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {

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

private module StepsInput implements Impl::Private::StepsInputSig {
Impl::Private::SummaryNode getSummaryNode(Node n) {
result = n.(FlowSummaryNode).getSummaryNode()
module Input2 implements Impl::Private::InputSig2 {
class SourceSinkReportingElement extends Element {
private Function getEnclosingFunction() {
result = this.(StmtParent).getEnclosingFunction()
or
this = result.getAParameter()
}

DataFlowCallable getEnclosingCallable() {
result.asSourceCallable() = this.getEnclosingFunction()
}
}

private SourceSinkReportingElement getSourceSinkArgumentElement(
Call call, Impl::Private::SummaryComponent sc
) {
exists(Position pos, int i |
sc = Impl::Private::SummaryComponent::argument(pos) and
i = pos.getArgumentIndex()
|
result = call.getArgument(i)
or
i = -1 and
result = call.getQualifier()
)
}

SourceSinkReportingElement getSourceEntryElement(
Impl::Public::SourceElement source, Impl::Private::SummaryComponentStack s
) {
s.headOfSingleton() = Impl::Private::SummaryComponent::return(_) and
result.(Call).getTarget() = source
or
exists(Position pos, Function f |
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
result = f.getParameter(pos.getArgumentIndex())
|
// TODO: callbacks
// exists(Call call |
// call.getTarget() = source and
// f = getSourceSinkArgumentElement(call, s.tail().headOfSingleton())
// )
// or
s.length() = 1 and
f = source
)
or
exists(Call call |
call.getTarget() = source and
result = getSourceSinkArgumentElement(call, s.headOfSingleton())
)
}

private ArgumentNode getSourceNodeArgument(Call c, Impl::Private::SummaryComponent sc) {
exists(Position pos, DataFlowCall call |
sc = Impl::Private::SummaryComponent::argument(pos) and
c = call.asCallInstruction().getUnconvertedResultExpression() and
result.argumentOf(call, pos)
)
}

bindingset[e, s]
Node getSourceExitNode(SourceSinkReportingElement e, Impl::Private::SummaryComponentStack s) {
exists(ReturnKind rk, DataFlowCall call |
s.head() = Impl::Private::SummaryComponent::return(rk) and
call.asCallInstruction().getUnconvertedResultExpression() = e and
result = getAnOutNode(call, rk)
)
or
result.(ParameterNode).getParameter() = e
or
exists(Call call, Impl::Private::SummaryComponent arg |
arg = s.headOfSingleton() and
e = getSourceSinkArgumentElement(call, arg) and
result.(PostUpdateNode).getPreUpdateNode() = getSourceNodeArgument(call, arg)
)
}

bindingset[e, sc]
Node getSinkEntryNode(SourceSinkReportingElement e, Impl::Private::SummaryComponent sc) { none() }

SourceSinkReportingElement getSinkExitElement(
Impl::Public::SinkElement sink, Impl::Private::SummaryComponent sc
) {
none()
}
}

private import Impl::Private::Make2<Input2> as Impl2

private module StepsInput implements Impl2::StepsInputSig {
Impl2::SummaryNode getSummaryNode(Node n) { result = n.(FlowSummaryNode).getSummaryNode() }

DataFlowCall getACall(Public::SummarizedCallable sc) {
result.getStaticCallTarget().getUnderlyingCallable() = sc
}
Expand All @@ -148,12 +234,6 @@ private module StepsInput implements Impl::Private::StepsInputSig {
pragma[only_bind_out](out.getIndirectionIndex())
)
}

DataFlowCallable getSourceNodeEnclosingCallable(Input::SourceBase source) { none() }

Node getSourceNode(Input::SourceBase source, Impl::Private::SummaryComponentStack s) { none() }

Node getSinkNode(Input::SinkBase sink, Impl::Private::SummaryComponent sc) { none() }
}

module SourceSinkInterpretationInput implements
Expand Down Expand Up @@ -270,8 +350,9 @@ module SourceSinkInterpretationInput implements

module Private {
import Impl::Private
import Impl2

module Steps = Impl::Private::Steps<StepsInput>;
module Steps = Impl2::Steps<StepsInput>;

module External {
import Impl::Private::External
Expand Down Expand Up @@ -310,3 +391,23 @@ module Private {
}

module Public = Impl::Public;

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

SourceModel() {
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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1527,18 +1527,25 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
*/
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }

/**
* Gets the summarized callable that this node belongs to.
*/
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
result = this.getSummaryNode().getSummarizedCallable()
/** 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())
result = this.getSummaryNode().getEnclosingCallable()
}

override Location getLocationImpl() { result = this.getSummarizedCallable().getLocation() }
override Location getLocationImpl() { result = this.getSummaryNode().getLocation() }

override string toStringImpl() { result = this.getSummaryNode().toString() }
}
Expand Down Expand Up @@ -1780,7 +1787,7 @@ class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
override predicate isSummaryParameterOf(
FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition p
) {
c = this.getSummarizedCallable() and
c = this.getSummaryNode().getSummarizedCallable() and
p = this.getPosition()
}
}
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