@@ -35,22 +35,54 @@ newtype TApplicationModeEndpoint =
3535 argExpr .isVararg ( ) and
3636 not exists ( int i | i < idx and call .getArgument ( i ) .( Argument ) .isVararg ( ) )
3737 )
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 )
3843 }
3944
4045/**
4146 * An endpoint is a node that is a candidate for modeling.
4247 */
4348abstract 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 ( ) ;
4555
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 ( ) ;
4762
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 ( ) ;
4969
5070 abstract Top asTop ( ) ;
5171
72+ /**
73+ * Converts the endpoint to a node that can be used in a data flow graph.
74+ */
5275 abstract DataFlow:: Node asNode ( ) ;
5376
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+
5486 abstract string toString ( ) ;
5587}
5688
@@ -63,7 +95,15 @@ class ExplicitArgument extends ApplicationModeEndpoint, TExplicitArgument {
6395
6496 ExplicitArgument ( ) { this = TExplicitArgument ( call , arg ) }
6597
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 ( ) }
67107
68108 override Top asTop ( ) { result = arg .asExpr ( ) }
69109
@@ -78,9 +118,13 @@ class InstanceArgument extends ApplicationModeEndpoint, TInstanceArgument {
78118
79119 InstanceArgument ( ) { this = TInstanceArgument ( call , arg ) }
80120
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 ( ) }
84128
85129 override Top asTop ( ) { if exists ( arg .asExpr ( ) ) then result = arg .asExpr ( ) else result = call }
86130
@@ -105,15 +149,78 @@ class ImplicitVarargsArray extends ApplicationModeEndpoint, TImplicitVarargsArra
105149
106150 ImplicitVarargsArray ( ) { this = TImplicitVarargsArray ( call , vararg , idx ) }
107151
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 + "]" }
109157
110- override Top asTop ( ) { result = this .getCall ( ) }
158+ override string getMaDOutput ( ) { none ( ) }
159+
160+ override Top asTop ( ) { result = call }
111161
112162 override DataFlow:: Node asNode ( ) { result = vararg }
113163
114164 override string toString ( ) { result = vararg .toString ( ) }
115165}
116166
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+
117224/**
118225 * A candidates implementation.
119226 *
@@ -161,20 +268,39 @@ module ApplicationCandidatesImpl implements SharedCharacteristics::CandidateSig
161268 isCustomSink ( e , kind ) and provenance = "custom-sink"
162269 }
163270
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+
164279 predicate isNeutral ( Endpoint e ) {
165280 exists ( string package , string type , string name , string signature |
166281 sinkSpec ( e , package , type , name , signature , _, _) and
167282 ExternalFlow:: neutralModel ( package , type , name , [ signature , "" ] , "sink" , _)
168283 )
169284 }
170285
286+ // XXX how to extend to support sources?
171287 additional predicate sinkSpec (
172288 Endpoint e , string package , string type , string name , string signature , string ext , string input
173289 ) {
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
176302 ext = "" and
177- input = AutomodelJavaUtil :: getArgumentForIndex ( e . getArgIndex ( ) )
303+ output = e . getMaDOutput ( )
178304 }
179305
180306 /**
@@ -229,11 +355,12 @@ class ApplicationModeMetadataExtractor extends string {
229355
230356 predicate hasMetadata (
231357 Endpoint e , string package , string type , string subtypes , string name , string signature ,
232- string input , string isVarargsArray
358+ string input , string output , string isVarargsArray
233359 ) {
234360 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
237364 package = callable .getDeclaringType ( ) .getPackage ( ) .getName ( ) and
238365 // we're using the erased types because the MaD convention is to not specify type parameters.
239366 // 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
266393
267394 override predicate appliesToEndpoint ( Endpoint e ) {
268395 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
271398 }
272399}
273400
@@ -313,9 +440,13 @@ private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASink
313440 IsMaDTaintStepCharacteristic ( ) { this = "taint step" }
314441
315442 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
319450 FlowSummaryImpl:: Private:: Steps:: summarySetterStep ( e .asNode ( ) , _, _, _)
320451 }
321452}
@@ -326,8 +457,8 @@ private class IsMaDTaintStepCharacteristic extends CharacteristicsImpl::NotASink
326457 * The reason is that we would expect data/taint flow into the method implementation to uncover
327458 * any sinks that are present there.
328459 */
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" }
331462
332463 override predicate appliesToEndpoint ( Endpoint e ) {
333464 ApplicationModeGetCallable:: getCallable ( e ) .fromSource ( )
@@ -354,6 +485,7 @@ private class NonPublicMethodCharacteristic extends CharacteristicsImpl::Uninter
354485 NonPublicMethodCharacteristic ( ) { this = "non-public method" }
355486
356487 override predicate appliesToEndpoint ( Endpoint e ) {
488+ e .getExtensibleType ( ) = "sinkModel" and
357489 not ApplicationModeGetCallable:: getCallable ( e ) .isPublic ( )
358490 }
359491}
@@ -376,6 +508,7 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
376508 }
377509
378510 override predicate appliesToEndpoint ( Endpoint e ) {
511+ e .getExtensibleType ( ) = "sinkModel" and
379512 not ApplicationCandidatesImpl:: isSink ( e , _, _) and
380513 exists ( Endpoint otherSink |
381514 ApplicationCandidatesImpl:: isSink ( otherSink , _, "manual" ) and
@@ -393,7 +526,10 @@ private class OtherArgumentToModeledMethodCharacteristic extends Characteristics
393526private class FunctionValueCharacteristic extends CharacteristicsImpl:: LikelyNotASinkCharacteristic {
394527 FunctionValueCharacteristic ( ) { this = "function value" }
395528
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+ }
397533}
398534
399535/**
@@ -407,7 +543,10 @@ private class CannotBeTaintedCharacteristic extends CharacteristicsImpl::LikelyN
407543{
408544 CannotBeTaintedCharacteristic ( ) { this = "cannot be tainted" }
409545
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+ }
411550
412551 /**
413552 * Holds if the node `n` is known as the predecessor in a modeled flow step.
0 commit comments