@@ -18,17 +18,35 @@ private class ReturnNodeExt extends DataFlow::Node {
18
18
kind = DataFlowImplCommon:: getParamReturnPosition ( this , _) .getKind ( )
19
19
}
20
20
21
- string getOutput ( ) {
22
- kind instanceof DataFlowImplCommon:: ValueReturnKind and
21
+ /**
22
+ * Gets the kind of the return node.
23
+ */
24
+ DataFlowImplCommon:: ReturnKindExt getKind ( ) { result = kind }
25
+ }
26
+
27
+ bindingset [ c]
28
+ private signature string printCallableParamSig ( Callable c , ParameterPosition p ) ;
29
+
30
+ private module PrintReturnNodeExt< printCallableParamSig / 2 printCallableParam> {
31
+ string getOutput ( ReturnNodeExt node ) {
32
+ node .getKind ( ) instanceof DataFlowImplCommon:: ValueReturnKind and
23
33
result = "ReturnValue"
24
34
or
25
35
exists ( ParameterPosition pos |
26
- pos = kind .( DataFlowImplCommon:: ParamUpdateReturnKind ) .getPosition ( ) and
27
- result = paramReturnNodeAsOutput ( returnNodeEnclosingCallable ( this ) , pos )
36
+ pos = node . getKind ( ) .( DataFlowImplCommon:: ParamUpdateReturnKind ) .getPosition ( ) and
37
+ result = printCallableParam ( returnNodeEnclosingCallable ( node ) , pos )
28
38
)
29
39
}
30
40
}
31
41
42
+ string getOutput ( ReturnNodeExt node ) {
43
+ result = PrintReturnNodeExt< paramReturnNodeAsOutput / 2 > :: getOutput ( node )
44
+ }
45
+
46
+ string getContentOutput ( ReturnNodeExt node ) {
47
+ result = PrintReturnNodeExt< paramReturnNodeAsContentOutput / 2 > :: getOutput ( node )
48
+ }
49
+
32
50
class DataFlowSummaryTargetApi extends SummaryTargetApi {
33
51
DataFlowSummaryTargetApi ( ) { not isUninterestingForDataFlowModels ( this ) }
34
52
}
@@ -71,7 +89,8 @@ private predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2
71
89
* Holds if content `c` is either a field, a synthetic field or language specific
72
90
* content of a relevant type or a container like content.
73
91
*/
74
- private predicate isRelevantContent ( DataFlow:: ContentSet c ) {
92
+ pragma [ nomagic]
93
+ private predicate isRelevantContent0 ( DataFlow:: ContentSet c ) {
75
94
isRelevantTypeInContent ( c ) or
76
95
containerContent ( c )
77
96
}
@@ -85,6 +104,16 @@ string parameterNodeAsInput(DataFlow::ParameterNode p) {
85
104
result = qualifierString ( ) and p instanceof InstanceParameterNode
86
105
}
87
106
107
+ /**
108
+ * Gets the MaD string representation of the parameter `p`
109
+ * when used in content flow.
110
+ */
111
+ string parameterNodeAsContentInput ( DataFlow:: ParameterNode p ) {
112
+ result = parameterContentAccess ( p .asParameter ( ) )
113
+ or
114
+ result = qualifierString ( ) and p instanceof InstanceParameterNode
115
+ }
116
+
88
117
/**
89
118
* Gets the MaD input string representation of `source`.
90
119
*/
@@ -170,7 +199,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
170
199
) {
171
200
exists ( DataFlow:: ContentSet c |
172
201
DataFlowImplCommon:: store ( node1 , c .getAStoreContent ( ) , node2 , _, _) and
173
- isRelevantContent ( c ) and
202
+ isRelevantContent0 ( c ) and
174
203
(
175
204
state1 instanceof TaintRead and state2 .( TaintStore ) .getStep ( ) = 1
176
205
or
@@ -180,7 +209,7 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
180
209
or
181
210
exists ( DataFlow:: ContentSet c |
182
211
DataFlowPrivate:: readStep ( node1 , c , node2 ) and
183
- isRelevantContent ( c ) and
212
+ isRelevantContent0 ( c ) and
184
213
state1 .( TaintRead ) .getStep ( ) + 1 = state2 .( TaintRead ) .getStep ( )
185
214
)
186
215
}
@@ -196,14 +225,17 @@ module PropagateFlowConfig implements DataFlow::StateConfigSig {
196
225
197
226
module PropagateFlow = TaintTracking:: GlobalWithState< PropagateFlowConfig > ;
198
227
228
+ /**
229
+ * Gets the summary model(s) of `api`, if there is flow from parameters to return value or parameter.
230
+ */
199
231
string captureThroughFlow0 (
200
232
DataFlowSummaryTargetApi api , DataFlow:: ParameterNode p , ReturnNodeExt returnNodeExt
201
233
) {
202
234
exists ( string input , string output |
203
235
p .getEnclosingCallable ( ) = api and
204
236
returnNodeExt .( DataFlow:: Node ) .getEnclosingCallable ( ) = api and
205
237
input = parameterNodeAsInput ( p ) and
206
- output = returnNodeExt . getOutput ( ) and
238
+ output = getOutput ( returnNodeExt ) and
207
239
input != output and
208
240
result = Printing:: asTaintModel ( api , input , output )
209
241
)
@@ -219,6 +251,69 @@ string captureThroughFlow(DataFlowSummaryTargetApi api) {
219
251
)
220
252
}
221
253
254
+ private module PropagateContentFlowConfig implements ContentDataFlow:: ConfigSig {
255
+ predicate isSource ( DataFlow:: Node source ) {
256
+ source instanceof DataFlow:: ParameterNode and
257
+ source .getEnclosingCallable ( ) instanceof DataFlowSummaryTargetApi
258
+ }
259
+
260
+ predicate isSink ( DataFlow:: Node sink ) {
261
+ sink instanceof ReturnNodeExt and
262
+ sink .getEnclosingCallable ( ) instanceof DataFlowSummaryTargetApi
263
+ }
264
+
265
+ predicate isAdditionalFlowStep = isAdditionalContentFlowStep / 2 ;
266
+
267
+ predicate isBarrier ( DataFlow:: Node n ) {
268
+ exists ( Type t | t = n .getType ( ) and not isRelevantType ( t ) )
269
+ }
270
+
271
+ int accessPathLimit ( ) { result = 2 }
272
+
273
+ predicate isRelevantContent ( DataFlow:: ContentSet s ) { isRelevantContent0 ( s ) }
274
+
275
+ DataFlow:: FlowFeature getAFeature ( ) {
276
+ result instanceof DataFlow:: FeatureEqualSourceSinkCallContext
277
+ }
278
+ }
279
+
280
+ private module PropagateContentFlow = ContentDataFlow:: Global< PropagateContentFlowConfig > ;
281
+
282
+ private string getContent ( PropagateContentFlow:: AccessPath ap , int i ) {
283
+ exists ( ContentSet head , PropagateContentFlow:: AccessPath tail |
284
+ head = ap .getHead ( ) and
285
+ tail = ap .getTail ( )
286
+ |
287
+ i = 0 and
288
+ result = "." + printContent ( head )
289
+ or
290
+ i > 0 and result = getContent ( tail , i - 1 )
291
+ )
292
+ }
293
+
294
+ private string printStoreAccessPath ( PropagateContentFlow:: AccessPath ap ) {
295
+ result = concat ( int i | | getContent ( ap , i ) , "" order by i )
296
+ }
297
+
298
+ private string printReadAccessPath ( PropagateContentFlow:: AccessPath ap ) {
299
+ result = concat ( int i | | getContent ( ap , i ) , "" order by i desc )
300
+ }
301
+
302
+ string captureContentFlow ( DataFlowSummaryTargetApi api ) {
303
+ exists (
304
+ DataFlow:: ParameterNode p , ReturnNodeExt returnNodeExt , string input , string output ,
305
+ PropagateContentFlow:: AccessPath reads , PropagateContentFlow:: AccessPath stores ,
306
+ boolean preservesValue
307
+ |
308
+ PropagateContentFlow:: flow ( p , reads , returnNodeExt , stores , preservesValue ) and
309
+ returnNodeExt .getEnclosingCallable ( ) = api and
310
+ input = parameterNodeAsContentInput ( p ) + printReadAccessPath ( reads ) and
311
+ output = getContentOutput ( returnNodeExt ) + printStoreAccessPath ( stores ) and
312
+ input != output and
313
+ result = Printing:: asModel ( api , input , output , preservesValue )
314
+ )
315
+ }
316
+
222
317
/**
223
318
* A dataflow configuration used for finding new sources.
224
319
* The sources are the already known existing sources and the sinks are the API return nodes.
@@ -261,7 +356,7 @@ string captureSource(DataFlowSourceTargetApi api) {
261
356
ExternalFlow:: sourceNode ( source , kind ) and
262
357
api = sink .getEnclosingCallable ( ) and
263
358
not irrelevantSourceSinkApi ( source .getEnclosingCallable ( ) , api ) and
264
- result = Printing:: asSourceModel ( api , sink . getOutput ( ) , kind )
359
+ result = Printing:: asSourceModel ( api , getOutput ( sink ) , kind )
265
360
)
266
361
}
267
362
0 commit comments