Skip to content

Commit 695d7a2

Browse files
committed
C++: Support for access path at sources and sinks.
1 parent 419ea8f commit 695d7a2

5 files changed

Lines changed: 113 additions & 26 deletions

File tree

cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ private import new.DataFlow
115115
private import semmle.code.cpp.controlflow.IRGuards
116116
private import semmle.code.cpp.ir.dataflow.internal.DataFlowPrivate as Private
117117
private import semmle.code.cpp.ir.dataflow.internal.DataFlowUtil
118+
private import semmle.code.cpp.ir.dataflow.internal.DataFlowNodes as Nodes
118119
private import internal.FlowSummaryImpl
119120
private import internal.FlowSummaryImpl::Public
120121
private import internal.FlowSummaryImpl::Private
@@ -952,9 +953,7 @@ private module Cached {
952953
*/
953954
cached
954955
predicate sourceNode(DataFlow::Node node, string kind, string model) {
955-
exists(SourceSinkInterpretationInput::InterpretNode n |
956-
isSourceNode(n, kind, model) and n.asNode() = node
957-
)
956+
node.(Nodes::FlowSummaryNode).isSource(kind, model)
958957
}
959958

960959
/**

cpp/ql/lib/semmle/code/cpp/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 90 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,11 @@ private import semmle.code.cpp.dataflow.ExternalFlow
1313
private import semmle.code.cpp.ir.IR
1414

1515
module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
16-
private import codeql.util.Void
17-
1816
class SummarizedCallableBase = Function;
1917

20-
class SourceBase extends Void {
21-
Location getLocation() { none() }
22-
}
18+
class SourceBase = Function;
2319

24-
class SinkBase = SourceBase;
20+
class SinkBase = Function;
2521

2622
class FlowSummaryCallBase = CallInstruction;
2723

@@ -134,35 +130,92 @@ module Input implements InputSig<Location, DataFlowImplSpecific::CppDataFlow> {
134130

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

137-
private module Input2 implements Impl::Private::InputSig2 {
138-
private import codeql.util.Void
133+
module Input2 implements Impl::Private::InputSig2 {
134+
class SourceSinkReportingElement extends Element {
135+
private Function getEnclosingFunction() {
136+
result = this.(StmtParent).getEnclosingFunction()
137+
or
138+
this = result.getAParameter()
139+
}
139140

140-
class SourceSinkReportingElement extends Void {
141-
Location getLocation() { none() }
141+
DataFlowCallable getEnclosingCallable() {
142+
result.asSourceCallable() = this.getEnclosingFunction()
143+
}
144+
}
142145

143-
DataFlowCallable getEnclosingCallable() { none() }
146+
private SourceSinkReportingElement getSourceSinkArgumentElement(
147+
Call call, Impl::Private::SummaryComponent sc
148+
) {
149+
exists(Position pos, int i |
150+
sc = Impl::Private::SummaryComponent::argument(pos) and
151+
i = pos.getArgumentIndex()
152+
|
153+
result = call.getArgument(i)
154+
or
155+
i = -1 and
156+
result = call.getQualifier()
157+
)
144158
}
145159

146-
bindingset[source, s]
147160
SourceSinkReportingElement getSourceEntryElement(
148161
Impl::Public::SourceElement source, Impl::Private::SummaryComponentStack s
149162
) {
150-
none()
163+
s.headOfSingleton() = Impl::Private::SummaryComponent::return(_) and
164+
result.(Call).getTarget() = source
165+
or
166+
exists(Position pos, Function f |
167+
s.head() = Impl::Private::SummaryComponent::parameter(pos) and
168+
result = f.getParameter(pos.getArgumentIndex())
169+
|
170+
// TODO: callbacks
171+
// exists(Call call |
172+
// call.getTarget() = source and
173+
// f = getSourceSinkArgumentElement(call, s.tail().headOfSingleton())
174+
// )
175+
// or
176+
s.length() = 1 and
177+
f = source
178+
)
179+
or
180+
exists(Call call |
181+
call.getTarget() = source and
182+
result = getSourceSinkArgumentElement(call, s.headOfSingleton())
183+
)
184+
}
185+
186+
private ArgumentNode getSourceNodeArgument(Call c, Impl::Private::SummaryComponent sc) {
187+
exists(Position pos, DataFlowCall call |
188+
sc = Impl::Private::SummaryComponent::argument(pos) and
189+
c = call.asCallInstruction().getUnconvertedResultExpression() and
190+
result.argumentOf(call, pos)
191+
)
151192
}
152193

153194
bindingset[e, s]
154195
Node getSourceExitNode(SourceSinkReportingElement e, Impl::Private::SummaryComponentStack s) {
155-
none()
196+
exists(ReturnKind rk, DataFlowCall call |
197+
s.head() = Impl::Private::SummaryComponent::return(rk) and
198+
call.asCallInstruction().getUnconvertedResultExpression() = e and
199+
result = getAnOutNode(call, rk)
200+
)
201+
or
202+
result.(ParameterNode).getParameter() = e
203+
or
204+
exists(Call call, Impl::Private::SummaryComponent arg |
205+
arg = s.headOfSingleton() and
206+
e = getSourceSinkArgumentElement(call, arg) and
207+
result.(PostUpdateNode).getPreUpdateNode() = getSourceNodeArgument(call, arg)
208+
)
156209
}
157210

211+
bindingset[e, sc]
212+
Node getSinkEntryNode(SourceSinkReportingElement e, Impl::Private::SummaryComponent sc) { none() }
213+
158214
SourceSinkReportingElement getSinkExitElement(
159215
Impl::Public::SinkElement sink, Impl::Private::SummaryComponent sc
160216
) {
161217
none()
162218
}
163-
164-
bindingset[e, sc]
165-
Node getSinkEntryNode(SourceSinkReportingElement e, Impl::Private::SummaryComponent sc) { none() }
166219
}
167220

168221
private import Impl::Private::Make2<Input2> as Impl2
@@ -338,3 +391,23 @@ module Private {
338391
}
339392

340393
module Public = Impl::Public;
394+
395+
private class SourceModel extends Public::SourceElement {
396+
private string namespace;
397+
private string type;
398+
private boolean subtypes;
399+
private string name;
400+
private string signature;
401+
private string ext;
402+
403+
SourceModel() {
404+
sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _, _) and
405+
this = interpretElement(namespace, type, subtypes, name, signature, ext)
406+
}
407+
408+
override predicate isSource(
409+
string output, string kind, Public::Provenance provenance, string model
410+
) {
411+
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance, model)
412+
}
413+
}

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowNodes.qll

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1527,13 +1527,20 @@ class FlowSummaryNode extends Node, TFlowSummaryNode {
15271527
*/
15281528
FlowSummaryImpl::Private::SummaryNode getSummaryNode() { this = TFlowSummaryNode(result) }
15291529

1530-
/**
1531-
* Gets the summarized callable that this node belongs to.
1532-
*/
1533-
FlowSummaryImpl::Public::SummarizedCallable getSummarizedCallable() {
1534-
result = this.getSummaryNode().getSummarizedCallable()
1530+
/** Holds if this node is a source node of kind `kind`. */
1531+
predicate isSource(string kind, string model) {
1532+
this.getSummaryNode().(FlowSummaryImpl::Private::SourceOutputNode).isEntry(kind, model)
1533+
}
1534+
1535+
/** Holds if this node is a sink node of kind `kind`. */
1536+
predicate isSink(string kind, string model) {
1537+
this.getSummaryNode().(FlowSummaryImpl::Private::SinkInputNode).isExit(kind, model)
15351538
}
15361539

1540+
/**
1541+
* Gets the enclosing callable. For a `FlowSummaryNode` this is always the
1542+
* summarized function this node is part of.
1543+
*/
15371544
override DataFlowCallable getEnclosingCallable() {
15381545
result = this.getSummaryNode().getEnclosingCallable()
15391546
}
@@ -1780,7 +1787,7 @@ class SummaryParameterNode extends AbstractParameterNode, FlowSummaryNode {
17801787
override predicate isSummaryParameterOf(
17811788
FlowSummaryImpl::Public::SummarizedCallable c, ParameterPosition p
17821789
) {
1783-
c = this.getSummarizedCallable() and
1790+
c = this.getSummaryNode().getSummarizedCallable() and
17841791
p = this.getPosition()
17851792
}
17861793
}

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,8 @@ private module Cached {
121121
// models-as-data summarized flow
122122
FlowSummaryImpl::Private::Steps::summaryJumpStep(n1.(FlowSummaryNode).getSummaryNode(),
123123
n2.(FlowSummaryNode).getSummaryNode())
124+
or
125+
FlowSummaryImpl::Private::Steps::sourceJumpStep(n1.(FlowSummaryNode).getSummaryNode(), n2)
124126
}
125127

126128
/**

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,12 @@ private module Cached {
160160
// models-as-data summarized flow
161161
FlowSummaryImpl::Private::Steps::summaryLocalStep(nodeFrom,
162162
nodeTo.(FlowSummaryNode).getSummaryNode(), true, model)
163+
or
164+
FlowSummaryImpl::Private::Steps::sourceLocalStep(nodeFrom.(FlowSummaryNode).getSummaryNode(),
165+
nodeTo, model)
166+
or
167+
FlowSummaryImpl::Private::Steps::sinkLocalStep(nodeFrom,
168+
nodeTo.(FlowSummaryNode).getSummaryNode(), model)
163169
}
164170

165171
private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) {

0 commit comments

Comments
 (0)