1
1
import java
2
+ private import semmle.code.java.frameworks.android.Android
2
3
private import semmle.code.java.dataflow.DataFlow
3
4
private import semmle.code.java.dataflow.ExternalFlow
4
5
private import semmle.code.java.dataflow.FlowSteps
6
+ private import semmle.code.java.dataflow.FlowSummary
7
+ private import semmle.code.java.dataflow.internal.BaseSSA as BaseSsa
5
8
6
9
/** The class `android.content.Intent`. */
7
10
class TypeIntent extends Class {
@@ -242,19 +245,52 @@ private class StartComponentMethodAccess extends MethodAccess {
242
245
243
246
/** Gets the intent argument of this call. */
244
247
Argument getIntentArg ( ) {
245
- result .getType ( ) instanceof TypeIntent and
248
+ (
249
+ result .getType ( ) instanceof TypeIntent or
250
+ result .getType ( ) .( Array ) .getElementType ( ) instanceof TypeIntent
251
+ ) and
246
252
result = this .getAnArgument ( )
247
253
}
248
254
249
255
/** Holds if this targets a component of type `targetType`. */
250
- predicate targetsComponentType ( RefType targetType ) {
256
+ predicate targetsComponentType ( AndroidComponent targetType ) {
251
257
exists ( NewIntent newIntent |
252
- DataFlow :: localExprFlow ( newIntent , this .getIntentArg ( ) ) and
258
+ reaches ( newIntent , this .getIntentArg ( ) ) and
253
259
newIntent .getClassArg ( ) .getType ( ) .( ParameterizedType ) .getATypeArgument ( ) = targetType
254
260
)
255
261
}
256
262
}
257
263
264
+ /**
265
+ * Holds if `src` reaches the intent argument `arg` of `StartComponentMethodAccess`
266
+ * through intra-procedural steps.
267
+ */
268
+ private predicate reaches ( Expr src , Argument arg ) {
269
+ any ( StartComponentMethodAccess ma ) .getIntentArg ( ) = arg and
270
+ src = arg
271
+ or
272
+ exists ( Expr mid , BaseSsa:: BaseSsaVariable ssa , BaseSsa:: BaseSsaUpdate upd |
273
+ reaches ( mid , arg ) and
274
+ mid = ssa .getAUse ( ) and
275
+ upd = ssa .getAnUltimateLocalDefinition ( ) and
276
+ src = upd .getDefiningExpr ( ) .( VariableAssign ) .getSource ( )
277
+ )
278
+ or
279
+ exists ( CastingExpr e | e .getExpr ( ) = src | reaches ( e , arg ) )
280
+ or
281
+ exists ( ChooseExpr e | e .getAResultExpr ( ) = src | reaches ( e , arg ) )
282
+ or
283
+ exists ( AssignExpr e | e .getSource ( ) = src | reaches ( e , arg ) )
284
+ or
285
+ exists ( ArrayCreationExpr e | e .getInit ( ) .getAnInit ( ) = src | reaches ( e , arg ) )
286
+ or
287
+ exists ( StmtExpr e | e .getResultExpr ( ) = src | reaches ( e , arg ) )
288
+ or
289
+ exists ( NotNullExpr e | e .getExpr ( ) = src | reaches ( e , arg ) )
290
+ or
291
+ exists ( WhenExpr e | e .getBranch ( _) .getAResult ( ) = src | reaches ( e , arg ) )
292
+ }
293
+
258
294
/**
259
295
* A value-preserving step from the intent argument of a `startActivity` call to
260
296
* a `getIntent` call in the activity the intent targeted in its constructor.
@@ -271,6 +307,87 @@ private class StartActivityIntentStep extends AdditionalValueStep {
271
307
}
272
308
}
273
309
310
+ /**
311
+ * Holds if `targetType` is targeted by an existing `StartComponentMethodAccess` call
312
+ * and it's identified by `id`.
313
+ */
314
+ private predicate isTargetableType ( AndroidComponent targetType , string id ) {
315
+ exists ( StartComponentMethodAccess ma | ma .targetsComponentType ( targetType ) ) and
316
+ targetType .getQualifiedName ( ) = id
317
+ }
318
+
319
+ private class StartActivitiesSyntheticCallable extends SyntheticCallable {
320
+ AndroidComponent targetType ;
321
+
322
+ StartActivitiesSyntheticCallable ( ) {
323
+ exists ( string id |
324
+ this = "android.content.Activity.startActivities()+" + id and
325
+ isTargetableType ( targetType , id )
326
+ )
327
+ }
328
+
329
+ override StartComponentMethodAccess getACall ( ) {
330
+ result .getMethod ( ) .hasName ( "startActivities" ) and
331
+ result .targetsComponentType ( targetType )
332
+ }
333
+
334
+ override predicate propagatesFlow (
335
+ SummaryComponentStack input , SummaryComponentStack output , boolean preservesValue
336
+ ) {
337
+ exists ( ActivityIntentSyntheticGlobal glob | glob .getTargetType ( ) = targetType |
338
+ input = SummaryComponentStack:: arrayElementOf ( SummaryComponentStack:: argument ( 0 ) ) and
339
+ output = SummaryComponentStack:: singleton ( SummaryComponent:: syntheticGlobal ( glob ) ) and
340
+ preservesValue = true
341
+ )
342
+ }
343
+ }
344
+
345
+ private class GetIntentSyntheticCallable extends SyntheticCallable {
346
+ AndroidComponent targetType ;
347
+
348
+ GetIntentSyntheticCallable ( ) {
349
+ exists ( string id |
350
+ this = "android.content.Activity.getIntent()+" + id and
351
+ isTargetableType ( targetType , id )
352
+ )
353
+ }
354
+
355
+ override Call getACall ( ) {
356
+ result .getCallee ( ) instanceof AndroidGetIntentMethod and
357
+ result .getEnclosingCallable ( ) .getDeclaringType ( ) = targetType
358
+ }
359
+
360
+ override predicate propagatesFlow (
361
+ SummaryComponentStack input , SummaryComponentStack output , boolean preservesValue
362
+ ) {
363
+ exists ( ActivityIntentSyntheticGlobal glob | glob .getTargetType ( ) = targetType |
364
+ input = SummaryComponentStack:: singleton ( SummaryComponent:: syntheticGlobal ( glob ) ) and
365
+ output = SummaryComponentStack:: return ( ) and
366
+ preservesValue = true
367
+ )
368
+ }
369
+ }
370
+
371
+ private class ActivityIntentSyntheticGlobal extends SummaryComponent:: SyntheticGlobal {
372
+ AndroidComponent targetType ;
373
+
374
+ ActivityIntentSyntheticGlobal ( ) {
375
+ exists ( string id |
376
+ this = "ActivityIntentSyntheticGlobal+" + id and
377
+ isTargetableType ( targetType , id )
378
+ )
379
+ }
380
+
381
+ AndroidComponent getTargetType ( ) { result = targetType }
382
+ }
383
+
384
+ private class RequiredComponentStackForStartActivities extends RequiredSummaryComponentStack {
385
+ override predicate required ( SummaryComponent head , SummaryComponentStack tail ) {
386
+ head = SummaryComponent:: arrayElement ( ) and
387
+ tail = SummaryComponentStack:: argument ( 0 )
388
+ }
389
+ }
390
+
274
391
/**
275
392
* A value-preserving step from the intent argument of a `sendBroadcast` call to
276
393
* the intent parameter in the `onReceive` method of the receiver the
0 commit comments