Skip to content

Commit e2521a3

Browse files
committed
Data flow: Synthesize parameter return nodes
1 parent 6233da3 commit e2521a3

File tree

9 files changed

+198
-113
lines changed

9 files changed

+198
-113
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -546,7 +546,7 @@ module ProductFlow {
546546
Flow1::PathGraph::edges(pred1, succ1, _, _) and
547547
exists(ReturnKindExt returnKind |
548548
succ1.getNode() = returnKind.getAnOutNode(call) and
549-
pred1.getNode().(ReturnNodeExt).getKind() = returnKind
549+
paramReturnNode(_, pred1.asParameterReturnNode(), _, returnKind)
550550
)
551551
}
552552

@@ -574,7 +574,7 @@ module ProductFlow {
574574
Flow2::PathGraph::edges(pred2, succ2, _, _) and
575575
exists(ReturnKindExt returnKind |
576576
succ2.getNode() = returnKind.getAnOutNode(call) and
577-
pred2.getNode().(ReturnNodeExt).getKind() = returnKind
577+
paramReturnNode(_, pred2.asParameterReturnNode(), _, returnKind)
578578
)
579579
}
580580

csharp/ql/src/utils/modelgenerator/internal/CaptureModels.qll

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@
66
private import CaptureModelsSpecific
77
private import CaptureModelsPrinting
88

9+
/**
10+
* A node from which flow can return to the caller. This is either a regular
11+
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
12+
*/
13+
private class ReturnNodeExt extends DataFlow::Node {
14+
private DataFlowImplCommon::ReturnKindExt kind;
15+
16+
ReturnNodeExt() {
17+
kind = DataFlowImplCommon::getValueReturnPosition(this).getKind() or
18+
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
19+
}
20+
21+
string getOutput() {
22+
kind instanceof DataFlowImplCommon::ValueReturnKind and
23+
result = "ReturnValue"
24+
or
25+
exists(ParameterPosition pos |
26+
pos = kind.(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
27+
result = paramReturnNodeAsOutput(returnNodeEnclosingCallable(this), pos)
28+
)
29+
}
30+
}
31+
932
class DataFlowTargetApi extends TargetApiSpecific {
1033
DataFlowTargetApi() { isRelevantForDataFlowModels(this) }
1134
}
@@ -65,7 +88,7 @@ string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific
6588
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
6689
*/
6790
string captureQualifierFlow(TargetApiSpecific api) {
68-
exists(DataFlowImplCommon::ReturnNodeExt ret |
91+
exists(ReturnNodeExt ret |
6992
api = returnNodeEnclosingCallable(ret) and
7093
isOwnInstanceAccessNode(ret)
7194
) and
@@ -130,7 +153,7 @@ module ThroughFlowConfig implements DataFlow::StateConfigSig {
130153
}
131154

132155
predicate isSink(DataFlow::Node sink, FlowState state) {
133-
sink instanceof DataFlowImplCommon::ReturnNodeExt and
156+
sink instanceof ReturnNodeExt and
134157
not isOwnInstanceAccessNode(sink) and
135158
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and
136159
(state instanceof TaintRead or state instanceof TaintStore)
@@ -171,14 +194,11 @@ private module ThroughFlow = TaintTracking::GlobalWithState<ThroughFlowConfig>;
171194
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
172195
*/
173196
string captureThroughFlow(DataFlowTargetApi api) {
174-
exists(
175-
DataFlow::ParameterNode p, DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input,
176-
string output
177-
|
197+
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output |
178198
ThroughFlow::flow(p, returnNodeExt) and
179199
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
180200
input = parameterNodeAsInput(p) and
181-
output = returnNodeAsOutput(returnNodeExt) and
201+
output = returnNodeExt.getOutput() and
182202
input != output and
183203
result = ModelPrinting::asTaintModel(api, input, output)
184204
)
@@ -196,7 +216,7 @@ module FromSourceConfig implements DataFlow::ConfigSig {
196216

197217
predicate isSink(DataFlow::Node sink) {
198218
exists(DataFlowTargetApi c |
199-
sink instanceof DataFlowImplCommon::ReturnNodeExt and
219+
sink instanceof ReturnNodeExt and
200220
sink.getEnclosingCallable() = c
201221
)
202222
}
@@ -214,12 +234,12 @@ private module FromSource = TaintTracking::Global<FromSourceConfig>;
214234
* Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`.
215235
*/
216236
string captureSource(DataFlowTargetApi api) {
217-
exists(DataFlow::Node source, DataFlow::Node sink, string kind |
237+
exists(DataFlow::Node source, ReturnNodeExt sink, string kind |
218238
FromSource::flow(source, sink) and
219239
ExternalFlow::sourceNode(source, kind) and
220240
api = sink.getEnclosingCallable() and
221241
isRelevantSourceKind(kind) and
222-
result = ModelPrinting::asSourceModel(api, returnNodeAsOutput(sink), kind)
242+
result = ModelPrinting::asSourceModel(api, sink.getOutput(), kind)
223243
)
224244
}
225245

csharp/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ private import semmle.code.csharp.frameworks.system.linq.Expressions
1111
import semmle.code.csharp.dataflow.internal.ExternalFlow as ExternalFlow
1212
import semmle.code.csharp.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
1313
import semmle.code.csharp.dataflow.internal.DataFlowPrivate as DataFlowPrivate
14+
import semmle.code.csharp.dataflow.internal.DataFlowDispatch as DataFlowDispatch
1415

1516
module DataFlow = CS::DataFlow;
1617

@@ -129,32 +130,24 @@ string parameterAccess(CS::Parameter p) {
129130

130131
class InstanceParameterNode = DataFlowPrivate::InstanceParameterNode;
131132

132-
pragma[nomagic]
133-
private CS::Parameter getParameter(DataFlowImplCommon::ReturnNodeExt node, ParameterPosition pos) {
134-
result = node.(DataFlow::Node).getEnclosingCallable().getParameter(pos.getPosition())
135-
}
133+
class ParameterPosition = DataFlowDispatch::ParameterPosition;
136134

137135
/**
138-
* Gets the MaD string representation of the the return node `node`.
136+
* Gets the MaD string represention of return through parameter at position
137+
* `pos` of callable `c`.
139138
*/
140-
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
141-
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
142-
then result = "ReturnValue"
143-
else
144-
exists(ParameterPosition pos |
145-
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition()
146-
|
147-
result = parameterAccess(getParameter(node, pos))
148-
or
149-
pos.isThisParameter() and
150-
result = qualifierString()
151-
)
139+
bindingset[c]
140+
string paramReturnNodeAsOutput(CS::Callable c, ParameterPosition pos) {
141+
result = parameterAccess(c.getParameter(pos.getPosition()))
142+
or
143+
pos.isThisParameter() and
144+
result = qualifierString()
152145
}
153146

154147
/**
155148
* Gets the enclosing callable of `ret`.
156149
*/
157-
CS::Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
150+
CS::Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
158151
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable()
159152
}
160153

go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,10 @@ module SourceSinkInterpretationInput implements
236236
/** Provides additional source specification logic. */
237237
bindingset[c]
238238
predicate interpretInput(string c, InterpretNode mid, InterpretNode node) {
239-
exists(int pos, ReturnNodeExt ret |
239+
exists(int pos, ReturnNode ret |
240240
parseReturn(c, pos) and
241241
ret = node.asNode() and
242-
ret.getKind().(ValueReturnKind).getKind() = getReturnKind(pos) and
242+
ret.getKind() = getReturnKind(pos) and
243243
mid.asCallable() = getNodeEnclosingCallable(ret)
244244
)
245245
or

java/ql/src/utils/modelgenerator/internal/CaptureModels.qll

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,29 @@
66
private import CaptureModelsSpecific
77
private import CaptureModelsPrinting
88

9+
/**
10+
* A node from which flow can return to the caller. This is either a regular
11+
* `ReturnNode` or a `PostUpdateNode` corresponding to the value of a parameter.
12+
*/
13+
private class ReturnNodeExt extends DataFlow::Node {
14+
private DataFlowImplCommon::ReturnKindExt kind;
15+
16+
ReturnNodeExt() {
17+
kind = DataFlowImplCommon::getValueReturnPosition(this).getKind() or
18+
kind = DataFlowImplCommon::getParamReturnPosition(this, _).getKind()
19+
}
20+
21+
string getOutput() {
22+
kind instanceof DataFlowImplCommon::ValueReturnKind and
23+
result = "ReturnValue"
24+
or
25+
exists(ParameterPosition pos |
26+
pos = kind.(DataFlowImplCommon::ParamUpdateReturnKind).getPosition() and
27+
result = paramReturnNodeAsOutput(returnNodeEnclosingCallable(this), pos)
28+
)
29+
}
30+
}
31+
932
class DataFlowTargetApi extends TargetApiSpecific {
1033
DataFlowTargetApi() { isRelevantForDataFlowModels(this) }
1134
}
@@ -65,7 +88,7 @@ string asInputArgument(DataFlow::Node source) { result = asInputArgumentSpecific
6588
* Gets the summary model of `api`, if it follows the `fluent` programming pattern (returns `this`).
6689
*/
6790
string captureQualifierFlow(TargetApiSpecific api) {
68-
exists(DataFlowImplCommon::ReturnNodeExt ret |
91+
exists(ReturnNodeExt ret |
6992
api = returnNodeEnclosingCallable(ret) and
7093
isOwnInstanceAccessNode(ret)
7194
) and
@@ -130,7 +153,7 @@ module ThroughFlowConfig implements DataFlow::StateConfigSig {
130153
}
131154

132155
predicate isSink(DataFlow::Node sink, FlowState state) {
133-
sink instanceof DataFlowImplCommon::ReturnNodeExt and
156+
sink instanceof ReturnNodeExt and
134157
not isOwnInstanceAccessNode(sink) and
135158
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable())) and
136159
(state instanceof TaintRead or state instanceof TaintStore)
@@ -171,14 +194,11 @@ private module ThroughFlow = TaintTracking::GlobalWithState<ThroughFlowConfig>;
171194
* Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
172195
*/
173196
string captureThroughFlow(DataFlowTargetApi api) {
174-
exists(
175-
DataFlow::ParameterNode p, DataFlowImplCommon::ReturnNodeExt returnNodeExt, string input,
176-
string output
177-
|
197+
exists(DataFlow::ParameterNode p, ReturnNodeExt returnNodeExt, string input, string output |
178198
ThroughFlow::flow(p, returnNodeExt) and
179199
returnNodeExt.(DataFlow::Node).getEnclosingCallable() = api and
180200
input = parameterNodeAsInput(p) and
181-
output = returnNodeAsOutput(returnNodeExt) and
201+
output = returnNodeExt.getOutput() and
182202
input != output and
183203
result = ModelPrinting::asTaintModel(api, input, output)
184204
)
@@ -196,7 +216,7 @@ module FromSourceConfig implements DataFlow::ConfigSig {
196216

197217
predicate isSink(DataFlow::Node sink) {
198218
exists(DataFlowTargetApi c |
199-
sink instanceof DataFlowImplCommon::ReturnNodeExt and
219+
sink instanceof ReturnNodeExt and
200220
sink.getEnclosingCallable() = c
201221
)
202222
}
@@ -214,12 +234,12 @@ private module FromSource = TaintTracking::Global<FromSourceConfig>;
214234
* Gets the source model(s) of `api`, if there is flow from an existing known source to the return of `api`.
215235
*/
216236
string captureSource(DataFlowTargetApi api) {
217-
exists(DataFlow::Node source, DataFlow::Node sink, string kind |
237+
exists(DataFlow::Node source, ReturnNodeExt sink, string kind |
218238
FromSource::flow(source, sink) and
219239
ExternalFlow::sourceNode(source, kind) and
220240
api = sink.getEnclosingCallable() and
221241
isRelevantSourceKind(kind) and
222-
result = ModelPrinting::asSourceModel(api, returnNodeAsOutput(sink), kind)
242+
result = ModelPrinting::asSourceModel(api, sink.getOutput(), kind)
223243
)
224244
}
225245

java/ql/src/utils/modelgenerator/internal/CaptureModelsSpecific.qll

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ private import semmle.code.java.dataflow.TaintTracking as Tt
1313
import semmle.code.java.dataflow.ExternalFlow as ExternalFlow
1414
import semmle.code.java.dataflow.internal.DataFlowImplCommon as DataFlowImplCommon
1515
import semmle.code.java.dataflow.internal.DataFlowPrivate as DataFlowPrivate
16+
import semmle.code.java.dataflow.internal.DataFlowDispatch as DataFlowDispatch
1617

1718
module DataFlow = Df::DataFlow;
1819

@@ -190,26 +191,23 @@ string parameterAccess(J::Parameter p) {
190191

191192
class InstanceParameterNode = DataFlow::InstanceParameterNode;
192193

194+
class ParameterPosition = DataFlowDispatch::ParameterPosition;
195+
193196
/**
194-
* Gets the MaD string represention of the the return node `node`.
197+
* Gets the MaD string represention of return through parameter at position
198+
* `pos` of callable `c`.
195199
*/
196-
string returnNodeAsOutput(DataFlowImplCommon::ReturnNodeExt node) {
197-
if node.getKind() instanceof DataFlowImplCommon::ValueReturnKind
198-
then result = "ReturnValue"
199-
else
200-
exists(int pos |
201-
pos = node.getKind().(DataFlowImplCommon::ParamUpdateReturnKind).getPosition()
202-
|
203-
result = parameterAccess(node.(DataFlow::Node).getEnclosingCallable().getParameter(pos))
204-
or
205-
result = qualifierString() and pos = -1
206-
)
200+
bindingset[c]
201+
string paramReturnNodeAsOutput(Callable c, ParameterPosition pos) {
202+
result = parameterAccess(c.getParameter(pos))
203+
or
204+
result = qualifierString() and pos = -1
207205
}
208206

209207
/**
210208
* Gets the enclosing callable of `ret`.
211209
*/
212-
Callable returnNodeEnclosingCallable(DataFlowImplCommon::ReturnNodeExt ret) {
210+
Callable returnNodeEnclosingCallable(DataFlow::Node ret) {
213211
result = DataFlowImplCommon::getNodeEnclosingCallable(ret).asCallable()
214212
}
215213

0 commit comments

Comments
 (0)