Merge pull request #10368 from jcogs33/android-deeplink-analysis

Java: Android deeplink analysis
This commit is contained in:
Jami
2022-10-07 14:32:05 -04:00
committed by GitHub
7 changed files with 461 additions and 44 deletions

View File

@@ -3,9 +3,7 @@ private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSteps
/**
* The class `android.content.Intent`.
*/
/** The class `android.content.Intent`. */
class TypeIntent extends Class {
TypeIntent() { this.hasQualifiedName("android.content", "Intent") }
}
@@ -15,23 +13,17 @@ class TypeComponentName extends Class {
TypeComponentName() { this.hasQualifiedName("android.content", "ComponentName") }
}
/**
* The class `android.app.Activity`.
*/
/** The class `android.app.Activity`. */
class TypeActivity extends Class {
TypeActivity() { this.hasQualifiedName("android.app", "Activity") }
}
/**
* The class `android.app.Service`.
*/
/** The class `android.app.Service`. */
class TypeService extends Class {
TypeService() { this.hasQualifiedName("android.app", "Service") }
}
/**
* The class `android.content.Context`.
*/
/** The class `android.content.Context`. */
class TypeContext extends RefType {
// Not inlining this makes it more likely to be used as a sentinel,
// which is useful when running Android queries on non-Android projects.
@@ -39,25 +31,19 @@ class TypeContext extends RefType {
TypeContext() { this.hasQualifiedName("android.content", "Context") }
}
/**
* The class `android.content.BroadcastReceiver`.
*/
/** The class `android.content.BroadcastReceiver`. */
class TypeBroadcastReceiver extends Class {
TypeBroadcastReceiver() { this.hasQualifiedName("android.content", "BroadcastReceiver") }
}
/**
* The method `Activity.getIntent`
*/
/** The method `Activity.getIntent` */
class AndroidGetIntentMethod extends Method {
AndroidGetIntentMethod() {
this.hasName("getIntent") and this.getDeclaringType() instanceof TypeActivity
}
}
/**
* The method `BroadcastReceiver.onReceive`.
*/
/** The method `BroadcastReceiver.onReceive`. */
class AndroidReceiveIntentMethod extends Method {
AndroidReceiveIntentMethod() {
this.hasName("onReceive") and this.getDeclaringType() instanceof TypeBroadcastReceiver
@@ -77,8 +63,10 @@ class AndroidServiceIntentMethod extends Method {
/**
* The method `Context.startActivity` or `startActivities`.
*
* DEPRECATED: Use `StartActivityMethod` instead.
*/
class ContextStartActivityMethod extends Method {
deprecated class ContextStartActivityMethod extends Method {
ContextStartActivityMethod() {
(this.hasName("startActivity") or this.hasName("startActivities")) and
this.getDeclaringType() instanceof TypeContext
@@ -86,16 +74,57 @@ class ContextStartActivityMethod extends Method {
}
/**
* Specifies that if an `Intent` is tainted, then so are its synthetic fields.
* The method `Context.startActivity`, `Context.startActivities`,
* `Activity.startActivity`,`Activity.startActivities`,
* `Activity.startActivityForResult`, `Activity.startActivityIfNeeded`,
* `Activity.startNextMatchingActivity`, `Activity.startActivityFromChild`,
* or `Activity.startActivityFromFragment`.
*/
class StartActivityMethod extends Method {
StartActivityMethod() {
this.getName().matches("start%Activit%") and
(
this.getDeclaringType() instanceof TypeContext or
this.getDeclaringType() instanceof TypeActivity
)
}
}
/**
* The method `Context.sendBroadcast`, `sendBroadcastAsUser`,
* `sendOrderedBroadcast`, `sendOrderedBroadcastAsUser`,
* `sendStickyBroadcast`, `sendStickyBroadcastAsUser`,
* `sendStickyOrderedBroadcast`, `sendStickyOrderedBroadcastAsUser`,
* or `sendBroadcastWithMultiplePermissions`.
*/
class SendBroadcastMethod extends Method {
SendBroadcastMethod() {
this.getName().matches("send%Broadcast%") and
this.getDeclaringType() instanceof TypeContext
}
}
/**
* The method `Context.startService`, `startForegroundService`,
* `bindIsolatedService`, `bindService`, or `bindServiceAsUser`.
*/
class StartServiceMethod extends Method {
StartServiceMethod() {
this.hasName([
"startService", "startForegroundService", "bindIsolatedService", "bindService",
"bindServiceAsUser"
]) and
this.getDeclaringType() instanceof TypeContext
}
}
/** Specifies that if an `Intent` is tainted, then so are its synthetic fields. */
private class IntentFieldsInheritTaint extends DataFlow::SyntheticFieldContent,
TaintInheritingContent {
IntentFieldsInheritTaint() { this.getField().matches("android.content.Intent.%") }
}
/**
* The method `Intent.getParcelableExtra`.
*/
/** The method `Intent.getParcelableExtra`. */
class IntentGetParcelableExtraMethod extends Method {
IntentGetParcelableExtraMethod() {
this.hasName("getParcelableExtra") and
@@ -157,9 +186,7 @@ private class BundleExtrasSyntheticField extends SyntheticField {
override RefType getType() { result instanceof AndroidBundle }
}
/**
* Holds if extras may be implicitly read from the Intent `node`.
*/
/** Holds if extras may be implicitly read from the Intent `node`. */
predicate allowIntentExtrasImplicitRead(DataFlow::Node node, DataFlow::Content c) {
node.getType() instanceof TypeIntent and
(
@@ -194,25 +221,90 @@ class GrantWriteUriPermissionFlag extends GrantUriPermissionFlag {
GrantWriteUriPermissionFlag() { this.hasName("FLAG_GRANT_WRITE_URI_PERMISSION") }
}
/** An instantiation of `android.content.Intent`. */
private class NewIntent extends ClassInstanceExpr {
NewIntent() { this.getConstructedType() instanceof TypeIntent }
/** Gets the `Class<?>` argument of this call. */
Argument getClassArg() {
result.getType() instanceof TypeClass and
result = this.getAnArgument()
}
}
/** A call to a method that starts an Android component. */
private class StartComponentMethodAccess extends MethodAccess {
StartComponentMethodAccess() {
this.getMethod().overrides*(any(StartActivityMethod m)) or
this.getMethod().overrides*(any(StartServiceMethod m)) or
this.getMethod().overrides*(any(SendBroadcastMethod m))
}
/** Gets the intent argument of this call. */
Argument getIntentArg() {
result.getType() instanceof TypeIntent and
result = this.getAnArgument()
}
/** Holds if this targets a component of type `targetType`. */
predicate targetsComponentType(RefType targetType) {
exists(NewIntent newIntent |
DataFlow::localExprFlow(newIntent, this.getIntentArg()) and
newIntent.getClassArg().getType().(ParameterizedType).getATypeArgument() = targetType
)
}
}
/**
* A value-preserving step from the Intent argument of a `startActivity` call to
* a `getIntent` call in the Activity the Intent pointed to in its constructor.
* A value-preserving step from the intent argument of a `startActivity` call to
* a `getIntent` call in the activity the intent targeted in its constructor.
*/
private class StartActivityIntentStep extends AdditionalValueStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess startActivity, MethodAccess getIntent, ClassInstanceExpr newIntent |
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and
exists(StartComponentMethodAccess startActivity, MethodAccess getIntent |
startActivity.getMethod().overrides*(any(StartActivityMethod m)) and
getIntent.getMethod().overrides*(any(AndroidGetIntentMethod m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
getIntent.getReceiverType() and
n1.asExpr() = startActivity.getArgument(0) and
startActivity.targetsComponentType(getIntent.getReceiverType()) and
n1.asExpr() = startActivity.getIntentArg() and
n2.asExpr() = getIntent
)
}
}
/**
* A value-preserving step from the intent argument of a `sendBroadcast` call to
* the intent parameter in the `onReceive` method of the receiver the
* intent targeted in its constructor.
*/
private class SendBroadcastReceiverIntentStep extends AdditionalValueStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(StartComponentMethodAccess sendBroadcast, Method onReceive |
sendBroadcast.getMethod().overrides*(any(SendBroadcastMethod m)) and
onReceive.overrides*(any(AndroidReceiveIntentMethod m)) and
sendBroadcast.targetsComponentType(onReceive.getDeclaringType()) and
n1.asExpr() = sendBroadcast.getIntentArg() and
n2.asParameter() = onReceive.getParameter(1)
)
}
}
/**
* A value-preserving step from the intent argument of a `startService` call to
* the intent parameter in an `AndroidServiceIntentMethod` of the service the
* intent targeted in its constructor.
*/
private class StartServiceIntentStep extends AdditionalValueStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(StartComponentMethodAccess startService, Method serviceIntent |
startService.getMethod().overrides*(any(StartServiceMethod m)) and
serviceIntent.overrides*(any(AndroidServiceIntentMethod m)) and
startService.targetsComponentType(serviceIntent.getDeclaringType()) and
n1.asExpr() = startService.getIntentArg() and
n2.asParameter() = serviceIntent.getParameter(0)
)
}
}
private class IntentBundleFlowSteps extends SummaryModelCsv {
override predicate row(string row) {
row =