Add the Intent parameter of onActivityResult as a source

This commit is contained in:
Tony Torralba
2021-10-26 10:43:10 +02:00
parent 520d8f5ec5
commit 211cb9370f
12 changed files with 215 additions and 6 deletions

View File

@@ -17,6 +17,7 @@ import semmle.code.java.frameworks.android.WebView
import semmle.code.java.frameworks.JaxWS
import semmle.code.java.frameworks.javase.WebSocket
import semmle.code.java.frameworks.android.Android
import semmle.code.java.frameworks.android.OnActivityResultSource
import semmle.code.java.frameworks.android.Intent
import semmle.code.java.frameworks.play.Play
import semmle.code.java.frameworks.spring.SpringWeb
@@ -264,3 +265,13 @@ class ExportedAndroidContentProviderInput extends RemoteFlowSource, AndroidConte
override string getSourceType() { result = "Exported Android content provider source" }
}
/**
* The data Intent parameter in the `onActivityResult` method in an Activity or Fragment that
* calls `startActivityForResult` with an implicit Intent.
*/
class OnActivityResultIntentSource extends OnActivityResultIncomingIntent, RemoteFlowSource {
OnActivityResultIntentSource() { isRemoteSource() }
override string getSourceType() { result = "Android onActivityResult incoming Intent" }
}

View File

@@ -1,16 +1,14 @@
/** Provides classes and predicates to track Android fragments. */
import java
/** The class `android.app.Fragment` */
class Fragment extends Class {
Fragment() { this.hasQualifiedName("android.app", "Fragment") }
/** An Android Fragment. */
class AndroidFragment extends Class {
AndroidFragment() { this.getASupertype*().hasQualifiedName("android.app", "Fragment") }
}
/** The method `instantiate` of the class `android.app.Fragment`. */
class FragmentInstantiateMethod extends Method {
FragmentInstantiateMethod() {
this.getDeclaringType() instanceof Fragment and
this.getDeclaringType() instanceof AndroidFragment and
this.hasName("instantiate")
}
}

View File

@@ -0,0 +1,70 @@
/** Provides a remote flow source for Android's `Activity.onActivityResult` method. */
import java
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.DataFlow5
private import semmle.code.java.frameworks.android.Android
private import semmle.code.java.frameworks.android.Fragment
private import semmle.code.java.frameworks.android.Intent
/**
* The data Intent parameter in the `onActivityResult` method.
*/
class OnActivityResultIncomingIntent extends DataFlow::Node {
OnActivityResultIncomingIntent() {
exists(Method onActivityResult |
onActivityResult.getDeclaringType() instanceof ActivityOrFragment and
onActivityResult.hasName("onActivityResult") and
this.asParameter() = onActivityResult.getParameter(2)
)
}
/**
* Holds if this node is a remote flow source.
*
* This is only a source when the Activity or Fragment that implements `onActivityResult` is
* also using an implicit Intent to start another Activity with `startActivityForResult`. This
* means that a malicious application can intercept it to start itself and return an arbitrary
* Intent to `onActivityResult`.
*/
predicate isRemoteSource() {
exists(ImplicitStartActivityForResultConf conf, DataFlow::Node sink |
conf.hasFlowTo(sink) and
DataFlow::getInstanceArgument(sink.asExpr().(Argument).getCall()).getType() =
this.getEnclosingCallable().getDeclaringType()
)
}
}
/**
* A data flow configuration for implicit intents being used in `startActivityForResult`.
*/
private class ImplicitStartActivityForResultConf extends DataFlow5::Configuration {
ImplicitStartActivityForResultConf() { this = "ImplicitStartActivityForResultConf" }
override predicate isSource(DataFlow::Node source) {
exists(ClassInstanceExpr cc |
cc.getConstructedType() instanceof TypeIntent and source.asExpr() = cc
)
}
override predicate isSink(DataFlow::Node sink) {
exists(ActivityOrFragment actOrFrag, MethodAccess startActivityForResult |
startActivityForResult.getMethod().hasName("startActivityForResult") and
startActivityForResult.getEnclosingCallable() = actOrFrag.getACallable() and
sink.asExpr() = startActivityForResult.getArgument(0)
)
}
override predicate isBarrier(DataFlow::Node barrier) {
barrier instanceof ExplicitIntentSanitizer
}
}
/** An Android Activity or Fragment. */
private class ActivityOrFragment extends Class {
ActivityOrFragment() {
this instanceof AndroidActivity or
this instanceof AndroidFragment
}
}