@@ -35,22 +35,54 @@ newtype TApplicationModeEndpoint =
35
35
argExpr .isVararg ( ) and
36
36
not exists ( int i | i < idx and call .getArgument ( i ) .( Argument ) .isVararg ( ) )
37
37
)
38
+ } or
39
+ TMethodReturnValue ( Call call ) { not call instanceof ConstructorCall } or
40
+ TOverriddenParameter ( Parameter p , Method overriddenMethod ) {
41
+ not p .getCallable ( ) .callsConstructor ( _) and
42
+ p .getCallable ( ) .( Method ) .overrides ( overriddenMethod )
38
43
}
39
44
40
45
/**
41
46
* An endpoint is a node that is a candidate for modeling.
42
47
*/
43
48
abstract private class ApplicationModeEndpoint extends TApplicationModeEndpoint {
44
- abstract predicate isArgOf ( Call c , int idx ) ;
49
+ /**
50
+ * Gets the callable to be modeled that this endpoint represents.
51
+ */
52
+ abstract Callable getCallable ( ) ;
53
+
54
+ abstract Call getCall ( ) ;
45
55
46
- Call getCall ( ) { this .isArgOf ( result , _) }
56
+ /**
57
+ * Gets the input (if any) for this endpoint, eg.: `Argument[0]`.
58
+ *
59
+ * For endpoints that are source candidates, this will be `none()`.
60
+ */
61
+ abstract string getMaDInput ( ) ;
47
62
48
- int getArgIndex ( ) { this .isArgOf ( _, result ) }
63
+ /**
64
+ * Gets the output (if any) for this endpoint, eg.: `ReturnValue`.
65
+ *
66
+ * For endpoints that are sink candidates, this will be `none()`.
67
+ */
68
+ abstract string getMaDOutput ( ) ;
49
69
50
70
abstract Top asTop ( ) ;
51
71
72
+ /**
73
+ * Converts the endpoint to a node that can be used in a data flow graph.
74
+ */
52
75
abstract DataFlow:: Node asNode ( ) ;
53
76
77
+ string getExtensibleType ( ) {
78
+ if not exists ( this .getMaDInput ( ) ) and exists ( this .getMaDOutput ( ) )
79
+ then result = "sourceModel"
80
+ else
81
+ if exists ( this .getMaDInput ( ) ) and not exists ( this .getMaDOutput ( ) )
82
+ then result = "sinkModel"
83
+ else none ( ) // if both exist, it would be a summaryModel (not yet supported)
84
+ }
85
+
54
86
abstract string toString ( ) ;
55
87
}
56
88
@@ -63,7 +95,15 @@ class ExplicitArgument extends ApplicationModeEndpoint, TExplicitArgument {
63
95
64
96
ExplicitArgument ( ) { this = TExplicitArgument ( call , arg ) }
65
97
66
- override predicate isArgOf ( Call c , int idx ) { c = call and this .asTop ( ) = c .getArgument ( idx ) }
98
+ override Callable getCallable ( ) { result = call .getCallee ( ) }
99
+
100
+ override Call getCall ( ) { result = call }
101
+
102
+ private int getArgIndex ( ) { this .asTop ( ) = call .getArgument ( result ) }
103
+
104
+ override string getMaDInput ( ) { result = "Argument[" + this .getArgIndex ( ) + "]" }
105
+
106
+ override string getMaDOutput ( ) { none ( ) }
67
107
68
108
override Top asTop ( ) { result = arg .asExpr ( ) }
69
109
@@ -78,9 +118,13 @@ class InstanceArgument extends ApplicationModeEndpoint, TInstanceArgument {
78
118
79
119
InstanceArgument ( ) { this = TInstanceArgument ( call , arg ) }
80
120
81
- override predicate isArgOf ( Call c , int idx ) {
82
- c = call and this .asTop ( ) = c .getQualifier ( ) and idx = - 1
83
- }
121
+ override Callable getCallable ( ) { result = call .getCallee ( ) }
122
+
123
+ override Call getCall ( ) { result = call }
124
+
125
+ override string getMaDInput ( ) { result = "Argument[this]" }
126
+
127
+ override string getMaDOutput ( ) { none ( ) }
84
128
85
129
override Top asTop ( ) { if exists ( arg .asExpr ( ) ) then result = arg .asExpr ( ) else result = call }
86
130
@@ -105,15 +149,78 @@ class ImplicitVarargsArray extends ApplicationModeEndpoint, TImplicitVarargsArra
105
149
106
150
ImplicitVarargsArray ( ) { this = TImplicitVarargsArray ( call , vararg , idx ) }
107
151
108
- override predicate isArgOf ( Call c , int i ) { c = call and i = idx }
152
+ override Callable getCallable ( ) { result = call .getCallee ( ) }
153
+
154
+ override Call getCall ( ) { result = call }
155
+
156
+ override string getMaDInput ( ) { result = "Argument[" + idx + "]" }
109
157
110
- override Top asTop ( ) { result = this .getCall ( ) }
158
+ override string getMaDOutput ( ) { none ( ) }
159
+
160
+ override Top asTop ( ) { result = call }
111
161
112
162
override DataFlow:: Node asNode ( ) { result = vararg }
113
163
114
164
override string toString ( ) { result = vararg .toString ( ) }
115
165
}
116
166
167
+ /**
168
+ * An endpoint that represents a method call. The `ReturnValue` of a method call
169
+ * may be a source.
170
+ */
171
+ class MethodReturnValue extends ApplicationModeEndpoint , TMethodReturnValue {
172
+ Call call ;
173
+
174
+ MethodReturnValue ( ) { this = TMethodReturnValue ( call ) }
175
+
176
+ override Callable getCallable ( ) { result = call .getCallee ( ) }
177
+
178
+ override Call getCall ( ) { result = call }
179
+
180
+ override string getMaDInput ( ) { none ( ) }
181
+
182
+ override string getMaDOutput ( ) { result = "ReturnValue" }
183
+
184
+ override Top asTop ( ) { result = call }
185
+
186
+ override DataFlow:: Node asNode ( ) { result .asExpr ( ) = call }
187
+
188
+ override string toString ( ) { result = call .toString ( ) }
189
+ }
190
+
191
+ /**
192
+ * An endpoint that represents a parameter of an overridden method that may be
193
+ * a source.
194
+ */
195
+ class OverriddenParameter extends ApplicationModeEndpoint , TOverriddenParameter {
196
+ Parameter p ;
197
+ Method overriddenMethod ;
198
+
199
+ OverriddenParameter ( ) { this = TOverriddenParameter ( p , overriddenMethod ) }
200
+
201
+ override Callable getCallable ( ) {
202
+ // NB: we're returning the overridden callable here. This means that the
203
+ // candidate model will be about the overridden method, not the overriding
204
+ // method. This is a more general model, that also applies to other
205
+ // subclasses of the overridden class.
206
+ result = overriddenMethod
207
+ }
208
+
209
+ override Call getCall ( ) { none ( ) }
210
+
211
+ private int getArgIndex ( ) { p .getCallable ( ) .getParameter ( result ) = p }
212
+
213
+ override string getMaDInput ( ) { none ( ) }
214
+
215
+ override string getMaDOutput ( ) { result = "Parameter[" + this .getArgIndex ( ) + "]" }
216
+
217
+ override Top asTop ( ) { result = p }
218
+
219
+ override DataFlow:: Node asNode ( ) { result .( DataFlow:: ParameterNode ) .asParameter ( ) = p }
220
+
221
+ override string toString ( ) { result = p .toString ( ) }
222
+ }
223
+
117
224
/**
118
225
* A candidates implementation.
119
226
*
@@ -161,20 +268,39 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
161
268
isCustomSink ( e , kind ) and provenance = "custom-sink"
162
269
}
163
270
271
+ predicate isSource ( Endpoint e , string kind , string provenance ) {
272
+ exists ( string package , string type , string name , string signature , string ext , string output |
273
+ sourceSpec ( e , package , type , name , signature , ext , output ) and
274
+ ExternalFlow:: sourceModel ( package , type , _, name , [ signature , "" ] , ext , output , kind ,
275
+ provenance )
276
+ )
277
+ }
278
+
164
279
predicate isNeutral ( Endpoint e ) {
165
280
exists ( string package , string type , string name , string signature |
166
281
sinkSpec ( e , package , type , name , signature , _, _) and
167
282
ExternalFlow:: neutralModel ( package , type , name , [ signature , "" ] , "sink" , _)
168
283
)
169
284
}
170
285
286
+ // XXX how to extend to support sources?
171
287
additional predicate sinkSpec (
172
288
Endpoint e , string package , string type , string name , string signature , string ext , string input
173
289
) {
174
- ApplicationModeGetCallable:: getCallable ( e ) .hasQualifiedName ( package , type , name ) and
175
- signature = ExternalFlow:: paramsString ( ApplicationModeGetCallable:: getCallable ( e ) ) and
290
+ e .getCallable ( ) .hasQualifiedName ( package , type , name ) and
291
+ signature = ExternalFlow:: paramsString ( e .getCallable ( ) ) and
292
+ ext = "" and
293
+ input = e .getMaDInput ( )
294
+ }
295
+
296
+ additional predicate sourceSpec (
297
+ Endpoint e , string package , string type , string name , string signature , string ext ,
298
+ string output
299
+ ) {
300
+ e .getCallable ( ) .hasQualifiedName ( package , type , name ) and
301
+ signature = ExternalFlow:: paramsString ( e .getCallable ( ) ) and
176
302
ext = "" and
177
- input = AutomodelJavaUtil :: getArgumentForIndex ( e . getArgIndex ( ) )
303
+ output = e . getMaDOutput ( )
178
304
}
179
305
180
306
/**
@@ -229,11 +355,12 @@ class ApplicationModeMetadataExtractor extends string {
229
355
230
356
predicate hasMetadata (
231
357
Endpoint e , string package , string type , string subtypes , string name , string signature ,
232
- string input , string isVarargsArray
358
+ string input , string output , string isVarargsArray
233
359
) {
234
360
exists ( Callable callable |
235
- e .getCall ( ) .getCallee ( ) = callable and
236
- input = AutomodelJavaUtil:: getArgumentForIndex ( e .getArgIndex ( ) ) and
361
+ e .getCallable ( ) = callable and
362
+ ( if exists ( e .getMaDInput ( ) ) then input = e .getMaDInput ( ) else input = "" ) and
363
+ ( if exists ( e .getMaDOutput ( ) ) then output = e .getMaDOutput ( ) else output = "" ) and
237
364
package = callable .getDeclaringType ( ) .getPackage ( ) .getName ( ) and
238
365
// we're using the erased types because the MaD convention is to not specify type parameters.
239
366
// Whether something is or isn't a sink doesn't usually depend on the type parameters.
@@ -266,8 +393,8 @@ private class UnexploitableIsCharacteristic extends CharacteristicsImpl::NotASin
266
393
267
394
override predicate appliesToEndpoint ( Endpoint e ) {
268
395
not ApplicationCandidatesImpl:: isSink ( e , _, _) and
269
- ApplicationModeGetCallable :: getCallable ( e ) .getName ( ) .matches ( "is%" ) and
270
- ApplicationModeGetCallable :: getCallable ( e ) .getReturnType ( ) instanceof BooleanType
396
+ e . getCallable ( ) .getName ( ) .matches ( "is%" ) and
397
+ e . getCallable ( ) .getReturnType ( ) instanceof BooleanType
271
398
}
272
399
}
273
400
@@ -313,9 +440,13 @@ private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASink
313
440
IsMaDTaintStepCharacteristic ( ) { this = "taint step" }
314
441
315
442
override predicate appliesToEndpoint ( Endpoint e ) {
316
- FlowSummaryImpl:: Private:: Steps:: summaryThroughStepValue ( e .asNode ( ) , _, _) or
317
- FlowSummaryImpl:: Private:: Steps:: summaryThroughStepTaint ( e .asNode ( ) , _, _) or
318
- FlowSummaryImpl:: Private:: Steps:: summaryGetterStep ( e .asNode ( ) , _, _, _) or
443
+ e .getExtensibleType ( ) = "sinkModel" and
444
+ FlowSummaryImpl:: Private:: Steps:: summaryThroughStepValue ( e .asNode ( ) , _, _)
445
+ or
446
+ FlowSummaryImpl:: Private:: Steps:: summaryThroughStepTaint ( e .asNode ( ) , _, _)
447
+ or
448
+ FlowSummaryImpl:: Private:: Steps:: summaryGetterStep ( e .asNode ( ) , _, _, _)
449
+ or
319
450
FlowSummaryImpl:: Private:: Steps:: summarySetterStep ( e .asNode ( ) , _, _, _)
320
451
}
321
452
}
@@ -326,8 +457,8 @@ private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASink
326
457
* The reason is that we would expect data/taint flow into the method implementation to uncover
327
458
* any sinks that are present there.
328
459
*/
329
- private class ArgumentToLocalCall extends CharacteristicsImpl:: UninterestingToModelCharacteristic {
330
- ArgumentToLocalCall ( ) { this = "argument to local call" }
460
+ private class LocalCall extends CharacteristicsImpl:: UninterestingToModelCharacteristic {
461
+ LocalCall ( ) { this = "local call" }
331
462
332
463
override predicate appliesToEndpoint ( Endpoint e ) {
333
464
ApplicationModeGetCallable:: getCallable ( e ) .fromSource ( )
@@ -354,6 +485,7 @@ private class NonPublicMethodCharacteristic extends CharacteristicsImpl::Uninter
354
485
NonPublicMethodCharacteristic ( ) { this = "non-public method" }
355
486
356
487
override predicate appliesToEndpoint ( Endpoint e ) {
488
+ e .getExtensibleType ( ) = "sinkModel" and
357
489
not ApplicationModeGetCallable:: getCallable ( e ) .isPublic ( )
358
490
}
359
491
}
@@ -376,6 +508,7 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
376
508
}
377
509
378
510
override predicate appliesToEndpoint ( Endpoint e ) {
511
+ e .getExtensibleType ( ) = "sinkModel" and
379
512
not ApplicationCandidatesImpl:: isSink ( e , _, _) and
380
513
exists ( Endpoint otherSink |
381
514
ApplicationCandidatesImpl:: isSink ( otherSink , _, "manual" ) and
@@ -393,7 +526,10 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
393
526
private class FunctionValueCharacteristic extends CharacteristicsImpl:: LikelyNotASinkCharacteristic {
394
527
FunctionValueCharacteristic ( ) { this = "function value" }
395
528
396
- override predicate appliesToEndpoint ( Endpoint e ) { e .asNode ( ) .asExpr ( ) instanceof FunctionalExpr }
529
+ override predicate appliesToEndpoint ( Endpoint e ) {
530
+ e .getExtensibleType ( ) = "sinkModel" and
531
+ e .asNode ( ) .asExpr ( ) instanceof FunctionalExpr
532
+ }
397
533
}
398
534
399
535
/**
@@ -407,7 +543,10 @@ private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyN
407
543
{
408
544
CannotBeTaintedCharacteristic ( ) { this = "cannot be tainted" }
409
545
410
- override predicate appliesToEndpoint ( Endpoint e ) { not this .isKnownOutNodeForStep ( e ) }
546
+ override predicate appliesToEndpoint ( Endpoint e ) {
547
+ e .getExtensibleType ( ) = "sinkModel" and
548
+ not this .isKnownOutNodeForStep ( e )
549
+ }
411
550
412
551
/**
413
552
* Holds if the node `n` is known as the predecessor in a modeled flow step.
0 commit comments