@@ -15,7 +15,6 @@ private import semmle.code.java.security.QueryInjection
1515private import semmle.code.java.security.RequestForgery
1616private import semmle.code.java.dataflow.internal.ModelExclusions as ModelExclusions
1717private import AutomodelJavaUtil as AutomodelJavaUtil
18- private import AutomodelSharedGetCallable as AutomodelSharedGetCallable
1918import AutomodelSharedCharacteristics as SharedCharacteristics
2019import AutomodelEndpointTypes as AutomodelEndpointTypes
2120
@@ -84,7 +83,7 @@ abstract class FrameworkModeEndpoint extends TFrameworkModeEndpoint {
8483 /**
8584 * Returns the callable that contains the endpoint.
8685 */
87- abstract Callable getEnclosingCallable ( ) ;
86+ abstract Callable getCallable ( ) ;
8887
8988 abstract Top asTop ( ) ;
9089
@@ -106,7 +105,7 @@ class ExplicitParameterEndpoint extends FrameworkModeEndpoint, TExplicitParamete
106105
107106 override string getParamName ( ) { result = param .getName ( ) }
108107
109- override Callable getEnclosingCallable ( ) { result = param .getCallable ( ) }
108+ override Callable getCallable ( ) { result = param .getCallable ( ) }
110109
111110 override Top asTop ( ) { result = param }
112111
@@ -126,7 +125,7 @@ class QualifierEndpoint extends FrameworkModeEndpoint, TQualifier {
126125
127126 override string getParamName ( ) { result = "this" }
128127
129- override Callable getEnclosingCallable ( ) { result = callable }
128+ override Callable getCallable ( ) { result = callable }
130129
131130 override Top asTop ( ) { result = callable }
132131
@@ -144,7 +143,7 @@ class ReturnValue extends FrameworkModeEndpoint, TReturnValue {
144143
145144 override string getParamName ( ) { none ( ) }
146145
147- override Callable getEnclosingCallable ( ) { result = callable }
146+ override Callable getCallable ( ) { result = callable }
148147
149148 override Top asTop ( ) { result = callable }
150149
@@ -163,7 +162,7 @@ class OverridableParameter extends FrameworkModeEndpoint, TOverridableParameter
163162
164163 override string getParamName ( ) { result = param .getName ( ) }
165164
166- override Callable getEnclosingCallable ( ) { result = method }
165+ override Callable getCallable ( ) { result = method }
167166
168167 override Top asTop ( ) { result = param }
169168
@@ -181,7 +180,7 @@ class OverridableQualifier extends FrameworkModeEndpoint, TOverridableQualifier
181180
182181 override string getParamName ( ) { result = "this" }
183182
184- override Callable getEnclosingCallable ( ) { result = m }
183+ override Callable getCallable ( ) { result = m }
185184
186185 override Top asTop ( ) { result = m }
187186
@@ -202,7 +201,9 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
202201
203202 class EndpointType = AutomodelEndpointTypes:: EndpointType ;
204203
205- class NegativeEndpointType = AutomodelEndpointTypes:: NegativeSinkType ;
204+ class SinkType = AutomodelEndpointTypes:: SinkType ;
205+
206+ class SourceType = AutomodelEndpointTypes:: SourceType ;
206207
207208 class RelatedLocation = Location:: Top ;
208209
@@ -244,8 +245,8 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
244245 additional predicate sinkSpec (
245246 Endpoint e , string package , string type , string name , string signature , string ext , string input
246247 ) {
247- e .getEnclosingCallable ( ) .hasQualifiedName ( package , type , name ) and
248- signature = ExternalFlow:: paramsString ( e .getEnclosingCallable ( ) ) and
248+ e .getCallable ( ) .hasQualifiedName ( package , type , name ) and
249+ signature = ExternalFlow:: paramsString ( e .getCallable ( ) ) and
249250 ext = "" and
250251 input = e .getMaDInput ( )
251252 }
@@ -254,8 +255,8 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
254255 Endpoint e , string package , string type , string name , string signature , string ext ,
255256 string output
256257 ) {
257- e .getEnclosingCallable ( ) .hasQualifiedName ( package , type , name ) and
258- signature = ExternalFlow:: paramsString ( e .getEnclosingCallable ( ) ) and
258+ e .getCallable ( ) .hasQualifiedName ( package , type , name ) and
259+ signature = ExternalFlow:: paramsString ( e .getCallable ( ) ) and
259260 ext = "" and
260261 output = e .getMaDOutput ( )
261262 }
@@ -267,10 +268,10 @@ module FrameworkCandidatesImpl implements SharedCharacteristics::CandidateSig {
267268 */
268269 RelatedLocation getRelatedLocation ( Endpoint e , RelatedLocationType type ) {
269270 type = MethodDoc ( ) and
270- result = e .getEnclosingCallable ( ) .( Documentable ) .getJavadoc ( )
271+ result = e .getCallable ( ) .( Documentable ) .getJavadoc ( )
271272 or
272273 type = ClassDoc ( ) and
273- result = e .getEnclosingCallable ( ) .getDeclaringType ( ) .( Documentable ) .getJavadoc ( )
274+ result = e .getCallable ( ) .getDeclaringType ( ) .( Documentable ) .getJavadoc ( )
274275 }
275276}
276277
@@ -292,16 +293,27 @@ class FrameworkModeMetadataExtractor extends string {
292293
293294 predicate hasMetadata (
294295 Endpoint e , string package , string type , string subtypes , string name , string signature ,
295- string input , string output , string parameterName
296+ string input , string output , string parameterName , string alreadyAiModeled ,
297+ string extensibleType
296298 ) {
297- ( if exists ( e .getParamName ( ) ) then parameterName = e .getParamName ( ) else parameterName = "" ) and
298- name = e .getEnclosingCallable ( ) .getName ( ) and
299- ( if exists ( e .getMaDInput ( ) ) then input = e .getMaDInput ( ) else input = "" ) and
300- ( if exists ( e .getMaDOutput ( ) ) then output = e .getMaDOutput ( ) else output = "" ) and
301- package = e .getEnclosingCallable ( ) .getDeclaringType ( ) .getPackage ( ) .getName ( ) and
302- type = e .getEnclosingCallable ( ) .getDeclaringType ( ) .getErasure ( ) .( RefType ) .nestedName ( ) and
303- subtypes = AutomodelJavaUtil:: considerSubtypes ( e .getEnclosingCallable ( ) ) .toString ( ) and
304- signature = ExternalFlow:: paramsString ( e .getEnclosingCallable ( ) )
299+ exists ( Callable callable | e .getCallable ( ) = callable |
300+ ( if exists ( e .getMaDInput ( ) ) then input = e .getMaDInput ( ) else input = "" ) and
301+ ( if exists ( e .getMaDOutput ( ) ) then output = e .getMaDOutput ( ) else output = "" ) and
302+ package = callable .getDeclaringType ( ) .getPackage ( ) .getName ( ) and
303+ // we're using the erased types because the MaD convention is to not specify type parameters.
304+ // Whether something is or isn't a sink doesn't usually depend on the type parameters.
305+ type = callable .getDeclaringType ( ) .getErasure ( ) .( RefType ) .nestedName ( ) and
306+ subtypes = AutomodelJavaUtil:: considerSubtypes ( callable ) .toString ( ) and
307+ name = callable .getName ( ) and
308+ signature = ExternalFlow:: paramsString ( callable ) and
309+ ( if exists ( e .getParamName ( ) ) then parameterName = e .getParamName ( ) else parameterName = "" ) and
310+ e .getExtensibleType ( ) = extensibleType
311+ ) and
312+ (
313+ not CharacteristicsImpl:: isModeled ( e , _, extensibleType , _) and alreadyAiModeled = ""
314+ or
315+ CharacteristicsImpl:: isModeled ( e , _, extensibleType , alreadyAiModeled )
316+ )
305317 }
306318}
307319
@@ -310,53 +322,79 @@ class FrameworkModeMetadataExtractor extends string {
310322 */
311323
312324/**
313- * A negative characteristic that indicates that an is-style boolean method is unexploitable even if it is a sink.
325+ * A negative characteristic that indicates that parameters of an is-style boolean method should not be considered sinks,
326+ * and its return value should not be considered a source.
314327 *
315328 * A sink is highly unlikely to be exploitable if its callable's name starts with `is` and the callable has a boolean return
316329 * type (e.g. `isDirectory`). These kinds of calls normally do only checks, and appear before the proper call that does
317330 * the dangerous/interesting thing, so we want the latter to be modeled as the sink.
318331 *
319332 * TODO: this might filter too much, it's possible that methods with more than one parameter contain interesting sinks
320333 */
321- private class UnexploitableIsCharacteristic extends CharacteristicsImpl:: NotASinkCharacteristic {
334+ private class UnexploitableIsCharacteristic extends CharacteristicsImpl:: NeitherSourceNorSinkCharacteristic
335+ {
322336 UnexploitableIsCharacteristic ( ) { this = "unexploitable (is-style boolean method)" }
323337
324338 override predicate appliesToEndpoint ( Endpoint e ) {
325- not FrameworkCandidatesImpl:: isSink ( e , _, _) and
326- e .getEnclosingCallable ( ) .getName ( ) .matches ( "is%" ) and
327- e .getEnclosingCallable ( ) .getReturnType ( ) instanceof BooleanType
339+ e .getCallable ( ) .getName ( ) .matches ( "is%" ) and
340+ e .getCallable ( ) .getReturnType ( ) instanceof BooleanType and
341+ (
342+ e .getExtensibleType ( ) = "sinkModel" and
343+ not FrameworkCandidatesImpl:: isSink ( e , _, _)
344+ or
345+ e .getExtensibleType ( ) = "sourceModel" and
346+ not FrameworkCandidatesImpl:: isSource ( e , _, _) and
347+ e .getMaDOutput ( ) = "ReturnValue"
348+ )
328349 }
329350}
330351
331352/**
332- * A negative characteristic that indicates that an existence-checking boolean method is unexploitable even if it is a
333- * sink .
353+ * A negative characteristic that indicates that parameters of an existence-checking boolean method should not be
354+ * considered sinks, and its return value should not be considered a source .
334355 *
335356 * A sink is highly unlikely to be exploitable if its callable's name is `exists` or `notExists` and the callable has a
336357 * boolean return type. These kinds of calls normally do only checks, and appear before the proper call that does the
337358 * dangerous/interesting thing, so we want the latter to be modeled as the sink.
338359 */
339- private class UnexploitableExistsCharacteristic extends CharacteristicsImpl:: NotASinkCharacteristic {
360+ private class UnexploitableExistsCharacteristic extends CharacteristicsImpl:: NeitherSourceNorSinkCharacteristic
361+ {
340362 UnexploitableExistsCharacteristic ( ) { this = "unexploitable (existence-checking boolean method)" }
341363
342364 override predicate appliesToEndpoint ( Endpoint e ) {
343- not FrameworkCandidatesImpl:: isSink ( e , _, _) and
344365 exists ( Callable callable |
345- callable = e .getEnclosingCallable ( ) and
366+ callable = e .getCallable ( ) and
346367 callable .getName ( ) .toLowerCase ( ) = [ "exists" , "notexists" ] and
347368 callable .getReturnType ( ) instanceof BooleanType
369+ |
370+ e .getExtensibleType ( ) = "sinkModel" and
371+ not FrameworkCandidatesImpl:: isSink ( e , _, _)
372+ or
373+ e .getExtensibleType ( ) = "sourceModel" and
374+ not FrameworkCandidatesImpl:: isSource ( e , _, _) and
375+ e .getMaDOutput ( ) = "ReturnValue"
348376 )
349377 }
350378}
351379
352380/**
353- * A negative characteristic that indicates that an endpoint is an argument to an exception, which is not a sink.
381+ * A negative characteristic that indicates that parameters of an exception method or constructor should not be considered sinks,
382+ * and its return value should not be considered a source.
354383 */
355- private class ExceptionCharacteristic extends CharacteristicsImpl:: NotASinkCharacteristic {
384+ private class ExceptionCharacteristic extends CharacteristicsImpl:: NeitherSourceNorSinkCharacteristic
385+ {
356386 ExceptionCharacteristic ( ) { this = "exception" }
357387
358388 override predicate appliesToEndpoint ( Endpoint e ) {
359- e .getEnclosingCallable ( ) .getDeclaringType ( ) .getASupertype * ( ) instanceof TypeThrowable
389+ e .getCallable ( ) .getDeclaringType ( ) .getASupertype * ( ) instanceof TypeThrowable and
390+ (
391+ e .getExtensibleType ( ) = "sinkModel" and
392+ not FrameworkCandidatesImpl:: isSink ( e , _, _)
393+ or
394+ e .getExtensibleType ( ) = "sourceModel" and
395+ not FrameworkCandidatesImpl:: isSource ( e , _, _) and
396+ e .getMaDOutput ( ) = "ReturnValue"
397+ )
360398 }
361399}
362400
@@ -368,6 +406,6 @@ private class NotAModelApi extends CharacteristicsImpl::UninterestingToModelChar
368406 NotAModelApi ( ) { this = "not a model API" }
369407
370408 override predicate appliesToEndpoint ( Endpoint e ) {
371- not e .getEnclosingCallable ( ) instanceof ModelExclusions:: ModelApi
409+ not e .getCallable ( ) instanceof ModelExclusions:: ModelApi
372410 }
373411}
0 commit comments