resolve merge conflict

This commit is contained in:
Jami Cogswell
2022-09-28 16:32:55 -04:00
committed by Tony Torralba
parent 11ce910c38
commit 9947b32446
6 changed files with 340 additions and 379 deletions

View File

@@ -1316,6 +1316,19 @@ class ClassInstanceExpr extends Expr, ConstructorCall, @classinstancexpr {
result = this.getAnArgument()
}
// ! remove below predicate after experimentation
/**
* Gets the argument provided to the constructor of this class instance creation expression
* of the specified Type.
*/
Expr getArgumentByType(Type type) {
exists(Argument arg |
arg = this.getAnArgument() and
arg.getType() = type and
result = arg
)
}
/**
* Gets a type argument provided to the constructor of this class instance creation expression.
*

View File

@@ -2,229 +2,81 @@
import java
private import semmle.code.java.frameworks.android.Intent
private import semmle.code.java.frameworks.android.AsyncTask
//private import semmle.code.java.frameworks.android.AsyncTask
private import semmle.code.java.frameworks.android.Android
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.FlowSteps
private import semmle.code.java.dataflow.ExternalFlow
//private import semmle.code.java.dataflow.ExternalFlow
//private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.xml.AndroidManifest
// ! if keeping this class, should prbly move to security folder.
// ! Remember to add 'private' annotation as needed to all new classes/predicates below.
/* ********* OTHER COMPONENTS (SERVICE, RECEIVER) *********** */
// ! and clean-up comments, etc. in below in general...
/**
* The class `android.app.Service`.
* A value-preserving step from the Intent argument of a method call that starts a component to
* a `getIntent` call or `Intent` parameter in the component that the Intent pointed to in its constructor.
*/
class TypeService extends Class {
TypeService() { this.hasQualifiedName("android.app", "Service") }
}
/**
* The method `Context.startService` or `Context.startForegroundService`.
*/
class ContextStartServiceMethod extends Method {
ContextStartServiceMethod() {
(this.hasName("startService") or this.hasName("startForegroundService")) and
this.getDeclaringType() instanceof TypeContext
}
}
/**
* A method of type Service that receives an Intent as a parameter.
* Namely: `Service.onStart`, `Service.onStartCommand`,
* `Service.onBind`, `Service.onRebind`
* `Service.onUnbind`, or
* `Service.onTaskRemoved`
*/
class AndroidServeIntentMethod extends Method {
AndroidServeIntentMethod() {
// ! experimental - make a DeepLink step that combine Activity, Service, Receiver, etc.
private class DeepLinkIntentStep extends AdditionalValueStep {
// DeepLinkIntentStep() {
// this instanceof StartActivityIntentStep_ContextAndActivity or
// this instanceof SendBroadcastReceiverIntentStep or
// this instanceof StartServiceIntentStep
// }
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
// ! simplify below
(
this.hasName("onStart") or
this.hasName("onStartCommand") or
// this.getName.matches("onStart%") or // could maybe switch with the above
this.hasName("onBind") or
this.hasName("onRebind") or
this.hasName("onUnbind") or
// this.getName.matches("on%bind") or // could maybe switch with the above
this.hasName("onTaskRemoved")
exists(StartServiceIntentStep startServiceIntentStep | startServiceIntentStep.step(n1, n2))
or
exists(SendBroadcastReceiverIntentStep sendBroadcastIntentStep |
sendBroadcastIntentStep.step(n1, n2)
)
or
exists(StartActivityIntentStep startActivityIntentStep | startActivityIntentStep.step(n1, n2))
) and
this.getDeclaringType() instanceof TypeService
}
}
/**
* The method `Service.onStart`, `Service.onStartCommand`,
* `Service.onBind`, `Service.onRebind`
* `Service.onUnbind`, or
* `Service.onTaskRemoved`
*/
class AndroidServeIntentMethod2 extends Method {
AndroidServeIntentMethod2() {
(
this instanceof ServiceOnStartMethod or
this instanceof ServiceOnBindMethod or
this instanceof ServiceOnUnbindMethod or
this instanceof ServiceOnTaskRemovedMethod
) and
this.getDeclaringType() instanceof TypeService
}
}
/**
* The method `Service.onStart` or `Service.onStartCommand`.
*/
class ServiceOnStartMethod extends Method {
ServiceOnStartMethod() {
(this.hasName("onStart") or this.hasName("onStartCommand")) and
this.getDeclaringType() instanceof TypeService
}
}
/**
* The method `Service.onBind` or `Service.onRebind`.
*/
class ServiceOnBindMethod extends Method {
ServiceOnBindMethod() {
(this.hasName("onBind") or this.hasName("onRebind")) and
this.getDeclaringType() instanceof TypeService
}
}
/**
* The method `Service.onUnbind`.
*/
class ServiceOnUnbindMethod extends Method {
ServiceOnUnbindMethod() {
this.hasName("onUnbind") and
this.getDeclaringType() instanceof TypeService
}
}
/**
* The method `Service.onTaskRemoved`.
*/
class ServiceOnTaskRemovedMethod extends Method {
ServiceOnTaskRemovedMethod() {
this.hasName("onTaskRemoved") and
this.getDeclaringType() instanceof TypeService
}
}
// ! update QLDoc more if needed (e.g. remove `onStart` reference)
/**
* A value-preserving step from the Intent argument of a `startService` call to
* the `Intent` Parameter in the `onStart` method of the Service the Intent pointed
* to in its constructor.
*/
class StartServiceIntentStep extends AdditionalValueStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess startService, Method onStart, ClassInstanceExpr newIntent |
startService.getMethod().overrides*(any(ContextStartServiceMethod m)) and
//onStart.overrides*(any(ServiceOnStartMethod m)) and
//onStart.overrides*(any(AndroidServeIntentMethod m)) and
onStart.overrides*(any(AndroidServeIntentMethod2 m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, startService.getArgument(0)) and
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
onStart.getDeclaringType() and
n1.asExpr() = startService.getArgument(0) and
n2.asParameter() = onStart.getParameter(0)
exists(AndroidComponent andComp |
andComp.getAndroidComponentXmlElement().(AndroidActivityXmlElement).hasDeepLink() and
n1.asExpr().getFile() = andComp.getFile() // ! ugly, see if better way to do this
)
}
}
// /**
// * The class `android.content.BroadcastReceiver`.
// */
// class TypeBroadcastReceiver extends Class {
// TypeBroadcastReceiver() { this.hasQualifiedName("android.content", "BroadcastReceiver") }
// }
// ! experimentation with global flow issue - REMOVE
/**
* The method `Context.sendBroadcast`.
* A value-preserving step from the Intent variable
* the `Intent` Parameter in the `startActivity`.
*/
class ContextSendBroadcastMethod extends Method {
ContextSendBroadcastMethod() {
this.getName().matches("send%Broadcast%") and // ! double-check this - seems to work based on quick-eval
this.getDeclaringType() instanceof TypeContext
}
}
// ! do I need to model this as well?
/**
* The method `BroadcastReceiver.peekService`.
*/
class BroadcastReceiverPeekServiceIntentMethod extends Method {
BroadcastReceiverPeekServiceIntentMethod() {
this.hasName("peekService") and this.getDeclaringType() instanceof TypeBroadcastReceiver
}
}
// /**
// * The method `BroadcastReceiver.onReceive`.
// */
// class AndroidReceiveIntentMethod extends Method {
// AndroidReceiveIntentMethod() {
// this.hasName("onReceive") and this.getDeclaringType() instanceof TypeBroadcastReceiver
// }
// }
/**
* A value-preserving step from the Intent argument of a `sendBroadcast` call to
* the `Intent` Parameter in the `onStart` method of the BroadcastReceiver the
* Intent pointed to in its constructor.
*/
class SendBroadcastReceiverIntentStep extends AdditionalValueStep {
class IntentVariableToStartActivityStep extends AdditionalValueStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess sendBroadcast, Method onReceive, ClassInstanceExpr newIntent |
sendBroadcast.getMethod().overrides*(any(ContextSendBroadcastMethod m)) and
onReceive.overrides*(any(AndroidReceiveIntentMethod m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, sendBroadcast.getArgument(0)) and
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
onReceive.getDeclaringType() and
n1.asExpr() = sendBroadcast.getArgument(0) and
n2.asParameter() = onReceive.getParameter(1)
exists(MethodAccess startActivity, Variable intentTypeTest |
(
// ! is there a better way to do this?
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) or
startActivity.getMethod().overrides*(any(ActivityStartActivityMethod m))
) and
intentTypeTest.getType() instanceof TypeIntent and
//startActivity.getFile().getBaseName() = "MainActivity.java" and // ! REMOVE
DataFlow::localExprFlow(intentTypeTest.getInitializer(), startActivity.getArgument(0)) and
n1.asExpr() = intentTypeTest.getInitializer() and
n2.asExpr() = startActivity.getArgument(0) // ! switch to getStartActivityIntentArg(startActivity)
)
}
}
/**
* The method `Activity.startActivity`.
/* ********************* INTENT METHODS, E.G. parseUri, getData, getExtras, etc. ********************* */
/*
* Below is a Draft/Test of modelling `Intent.parseUri`, `Intent.getData`,
* and `Intent.getExtras` methods
*/
class ActivityStartActivityMethod extends Method {
ActivityStartActivityMethod() {
// should capture all `startAct` methods in the Activity class
// except for `startNextMatchingActivity`, which I'm leaving out for now since seems potentially more complicated
this.getName().matches("startActivit%") and
this.getDeclaringType() instanceof TypeActivity
}
}
/**
* A value-preserving step from the Intent argument of a `startActivity` call from
* the Activity classs (not Context like the original StartActivityIntentStep in Intent.qll)
* to a `getIntent` call in the Activity the Intent pointed to in its constructor.
*/
private class StartActivityIntentStep_ActivityClass extends AdditionalValueStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess startActivity, MethodAccess getIntent, ClassInstanceExpr newIntent |
startActivity.getMethod().overrides*(any(ActivityStartActivityMethod m)) and
getIntent.getMethod().overrides*(any(AndroidGetIntentMethod m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and // ! startActivityFromChild and startActivityFromFragment have Intent as argument(1)...
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
getIntent.getReceiverType() and
n1.asExpr() = startActivity.getArgument(0) and // ! startActivityFromChild and startActivityFromFragment have Intent as argument(1)...
n2.asExpr() = getIntent
)
}
}
/* ********* INTENT METHODS, E.G. parseUri, getData, getExtras, etc. *********** */
// ! Check if can use pre-existing Synthetic Field instead of the below.
// ! Check if can use pre-existing Synthetic Field.
/**
* The method `Intent.get%Extra` or `Intent.getExtras`.
*/
class AndroidGetExtrasMethod extends Method {
AndroidGetExtrasMethod() {
(this.hasName("getExtras") or this.getName().matches("get%Extra")) and // ! switch to get%Extra% instead, I think wildcard holds for nothing there
this.getName().matches("get%Extra%") and
this.getDeclaringType() instanceof TypeIntent
}
}
@@ -243,64 +95,61 @@ class AndroidGetDataMethod extends Method {
*/
class AndroidParseUriMethod extends Method {
AndroidParseUriMethod() {
(this.hasName("parseUri") or this.hasName("getIntent")) and // getIntent for older versions before deprecation to parseUri
(this.hasName("parseUri") or this.hasName("getIntent")) and // ! Note to self: getIntent for older versions before deprecation to parseUri
this.getDeclaringType() instanceof TypeIntent
}
}
/**
* A taint step from the Intent argument of a `startActivity` call to
* a `Intent.parseUri` call in the Activity the Intent pointed to in its constructor.
*/
private class StartActivityParseUriStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess startActivity, MethodAccess parseUri, ClassInstanceExpr newIntent |
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and
parseUri.getMethod().overrides*(any(AndroidParseUriMethod m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
parseUri.getReceiverType() and
n1.asExpr() = startActivity.getArgument(0) and
n2.asExpr() = parseUri
)
}
}
/**
* A taint step from the Intent argument of a `startActivity` call to
* a `Intent.get%Extra%` call in the Activity the Intent pointed to in its constructor.
*/
private class StartActivityGetDataStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess startActivity, MethodAccess getData, ClassInstanceExpr newIntent |
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and
getData.getMethod().overrides*(any(AndroidGetDataMethod m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
getData.getReceiverType() and
n1.asExpr() = startActivity.getArgument(0) and
n2.asExpr() = getData
)
}
}
/**
* A taint step from the Intent argument of a `startActivity` call to
* a `Intent.getData` call in the Activity the Intent pointed to in its constructor.
*/
private class StartActivityGetExtrasStep extends AdditionalTaintStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess startActivity, MethodAccess getExtras, ClassInstanceExpr newIntent |
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and
getExtras.getMethod().overrides*(any(AndroidGetExtrasMethod m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
getExtras.getReceiverType() and
n1.asExpr() = startActivity.getArgument(0) and
n2.asExpr() = getExtras
)
}
}
// /**
// * A taint step from the Intent argument of a `startActivity` call to
// * a `Intent.parseUri` call in the Activity the Intent pointed to in its constructor.
// */
// private class StartActivityParseUriStep extends AdditionalTaintStep {
// override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
// exists(MethodAccess startActivity, MethodAccess parseUri, ClassInstanceExpr newIntent |
// startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and
// parseUri.getMethod().overrides*(any(AndroidParseUriMethod m)) and
// newIntent.getConstructedType() instanceof TypeIntent and
// DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and
// newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
// parseUri.getReceiverType() and
// n1.asExpr() = startActivity.getArgument(0) and
// n2.asExpr() = parseUri
// )
// }
// }
// /**
// * A taint step from the Intent argument of a `startActivity` call to
// * a `Intent.get%Extra%` call in the Activity the Intent pointed to in its constructor.
// */
// private class StartActivityGetDataStep extends AdditionalTaintStep {
// override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
// exists(MethodAccess startActivity, MethodAccess getData, ClassInstanceExpr newIntent |
// startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and
// getData.getMethod().overrides*(any(AndroidGetDataMethod m)) and
// newIntent.getConstructedType() instanceof TypeIntent and
// DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and
// newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
// getData.getReceiverType() and
// n1.asExpr() = startActivity.getArgument(0) and
// n2.asExpr() = getData
// )
// }
// }
// /**
// * A taint step from the Intent argument of a `startActivity` call to
// * a `Intent.getData` call in the Activity the Intent pointed to in its constructor.
// */
// private class StartActivityGetExtrasStep extends AdditionalTaintStep {
// override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
// exists(MethodAccess startActivity, MethodAccess getExtras, ClassInstanceExpr newIntent |
// startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and
// getExtras.getMethod().overrides*(any(AndroidGetExtrasMethod m)) and
// newIntent.getConstructedType() instanceof TypeIntent and
// DataFlow::localExprFlow(newIntent, startActivity.getArgument(0)) and
// newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
// getExtras.getReceiverType() and
// n1.asExpr() = startActivity.getArgument(0) and
// n2.asExpr() = getExtras
// )
// }
// }

View File

@@ -3,6 +3,8 @@ private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.FlowSteps
// ! Remember to add 'private' annotation as needed to all new classes/predicates below.
// ! and clean-up comments, etc. in below in general...
/**
* The class `android.content.Intent`.
*/
@@ -64,6 +66,38 @@ class AndroidReceiveIntentMethod extends Method {
}
}
// ! confirm if peekService should be modelled since it takes an Intent as a parameter
/**
* The method `BroadcastReceiver.peekService`.
*/
class BroadcastReceiverPeekServiceIntentMethod extends Method {
BroadcastReceiverPeekServiceIntentMethod() {
this.hasName("peekService") and this.getDeclaringType() instanceof TypeBroadcastReceiver
}
}
// ! potentially reword the below QLDoc
/**
* A method of type Service that receives an Intent as a parameter.
* Namely, `Service.onStart`, `onStartCommand`, `onBind`, `onRebind`
* `onUnbind`, or `onTaskRemoved`
*/
class AndroidServiceIntentMethod extends Method {
AndroidServiceIntentMethod() {
(
// this.hasName("onStart") or
// this.hasName("onStartCommand") or
this.getName().matches("onStart%") or
// this.hasName("onBind") or
// this.hasName("onRebind") or
// this.hasName("onUnbind") or
this.getName().matches("on%ind") or
this.hasName("onTaskRemoved")
) and
this.getDeclaringType() instanceof TypeService
}
}
/**
* The method `Service.onStart`, `onStartCommand`,
* `onBind`, `onRebind`, `onUnbind`, or `onTaskRemoved`.
@@ -85,6 +119,51 @@ class ContextStartActivityMethod extends Method {
}
}
// ! finish QLDoc
/**
* The method `Activity.startActivity` or ...
*/
class ActivityStartActivityMethod extends Method {
ActivityStartActivityMethod() {
// ! captures all `startAct` methods in the Activity class
this.getName().matches("start%Activit%") and // ! better to list all instead of using matches for any reason?
this.getDeclaringType() instanceof TypeActivity
}
}
/**
* The method `Context.sendBroadcast`.
*/
class ContextSendBroadcastMethod extends Method {
ContextSendBroadcastMethod() {
this.getName().matches("send%Broadcast%") and // ! Note to self: matches the 9 sendBroadcast methods
this.getDeclaringType() instanceof TypeContext
}
}
// ! update below QLDoc
/**
* The method `Context.startService`, `startForegroundService`,
* `bindIsolatedService`, `bindService`, or `bindServiceAsUser`.
* From https://developer.android.com/reference/android/app/Service:
* "Services can be started with Context.startService() and Context.bindService()."
*/
class ContextStartServiceMethod extends Method {
ContextStartServiceMethod() {
(
// this.hasName("startService") or
// this.hasName("startForegroundService") or
this.getName().matches("start%Service")
or
// this.hasName("bindIsolatedService") or
// this.hasName("bindService") or
// this.hasName("bindServiceAsUser")
this.getName().matches("bind%Service%")
) and
this.getDeclaringType() instanceof TypeContext
}
}
/**
* Specifies that if an `Intent` is tainted, then so are its synthetic fields.
*/
@@ -194,25 +273,115 @@ class GrantWriteUriPermissionFlag extends GrantUriPermissionFlag {
GrantWriteUriPermissionFlag() { this.hasName("FLAG_GRANT_WRITE_URI_PERMISSION") }
}
// ! OLD VERSION
// /**
// * 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.
// */
// 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
// 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
// n2.asExpr() = getIntent
// )
// }
// }
/**
* 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.
*/
private class StartActivityIntentStep extends AdditionalValueStep {
class StartActivityIntentStep extends AdditionalValueStep {
// ! startActivityFromChild and startActivityFromFragment have Intent as argument(1),
// ! but rest have Intent as argument(0)...
// ! startActivityFromChild and startActivityFromFragment are also deprecated and
// ! may need to look into modelling androidx.fragment.app.Fragment.startActivity() as well
private Argument getStartActivityIntentArg(MethodAccess startActMethodAccess) {
if
startActMethodAccess.getMethod().hasName("startActivityFromChild") or
startActMethodAccess.getMethod().hasName("startActivityFromFragment")
then result = startActMethodAccess.getArgument(1)
else result = startActMethodAccess.getArgument(0)
}
// ! Intent has two constructors with Class<?> parameter, only the first one with argument
// ! at position 1 was modelled before leading to lost flow. The second constructor with
// ! argument at position 3 needs to be modelled as well.
// ! See https://developer.android.com/reference/android/content/Intent#public-constructors
private Argument getIntentConstructorClassArg(ClassInstanceExpr intent) {
if intent.getNumArgument() = 2
then result = intent.getArgument(1)
else result = intent.getArgument(3)
}
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess startActivity, MethodAccess getIntent, ClassInstanceExpr newIntent |
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) and
(
// ! is there a better way to do this?
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) or
startActivity.getMethod().overrides*(any(ActivityStartActivityMethod 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() =
DataFlow::localExprFlow(newIntent, getStartActivityIntentArg(startActivity)) and
getIntentConstructorClassArg(newIntent).getType().(ParameterizedType).getATypeArgument() =
getIntent.getReceiverType() and
n1.asExpr() = startActivity.getArgument(0) and
// ! below uses predicate `getArgumentByType` that I added to the Expr.qll lib, prbly should not add new predicate there.
// argType.getName().matches("Class<%>") and
// newIntent.getArgumentByType(argType).getType().(ParameterizedType).getATypeArgument() =
// getIntent.getReceiverType() and
n1.asExpr() = getStartActivityIntentArg(startActivity) and
n2.asExpr() = getIntent
)
}
}
/**
* A value-preserving step from the Intent argument of a `sendBroadcast` call to
* the `Intent` Parameter in the `onStart` method of the BroadcastReceiver the
* Intent pointed to in its constructor.
*/
class SendBroadcastReceiverIntentStep extends AdditionalValueStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess sendBroadcast, Method onReceive, ClassInstanceExpr newIntent |
sendBroadcast.getMethod().overrides*(any(ContextSendBroadcastMethod m)) and
onReceive.overrides*(any(AndroidReceiveIntentMethod m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, sendBroadcast.getArgument(0)) and
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
onReceive.getDeclaringType() and
n1.asExpr() = sendBroadcast.getArgument(0) and
n2.asParameter() = onReceive.getParameter(1)
)
}
}
// ! potentially update QLDoc (e.g. remove `onStart` reference)
/**
* A value-preserving step from the Intent argument of a `startService` call to
* the `Intent` Parameter in the `onStart` method of the Service the Intent pointed
* to in its constructor.
*/
class StartServiceIntentStep extends AdditionalValueStep {
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
exists(MethodAccess startService, Method serviceIntent, ClassInstanceExpr newIntent |
startService.getMethod().overrides*(any(ContextStartServiceMethod m)) and
serviceIntent.overrides*(any(AndroidServiceIntentMethod m)) and
newIntent.getConstructedType() instanceof TypeIntent and
DataFlow::localExprFlow(newIntent, startService.getArgument(0)) and
newIntent.getArgument(1).getType().(ParameterizedType).getATypeArgument() =
serviceIntent.getDeclaringType() and
n1.asExpr() = startService.getArgument(0) and
n2.asParameter() = serviceIntent.getParameter(0)
)
}
}
private class IntentBundleFlowSteps extends SummaryModelCsv {
override predicate row(string row) {
row =

View File

@@ -130,11 +130,12 @@ class AndroidApplicationXmlElement extends XmlElement {
class AndroidActivityXmlElement extends AndroidComponentXmlElement {
AndroidActivityXmlElement() { this.getName() = "activity" }
// ! Double-check that no other components can have deep links.
// ! Consider moving this to its own .qll file like for Implicit Export Query.
// ! Also double-check that the below actions and categories are REQUIRED for it to
// ! count as a deep link versus just recommended (e.g. should I just look for the
// ! Consider moving this to its own .qll file under `security` like for Implicit Export Query.
// ! Double-check that the below actions and categories are REQUIRED for it to
// ! count as a deep link versus just recommended (e.g. should I just look at the
// ! data element instead?).
// ! Reference: https://developer.android.com/training/app-links/deep-linking#adding-filters
// ! Note: not excluding App Links since those are a subset of deep links that can still cause issues.
/**
* Holds if this `<activity>` element has a deep link.
*/

View File

@@ -9,118 +9,49 @@
* @precision high
*/
// * experiment with StartActivityIntentStep
// import java
// import semmle.code.xml.AndroidManifest
// import semmle.code.java.frameworks.android.Android
// import semmle.code.java.frameworks.android.Intent
// import semmle.code.java.frameworks.android.AsyncTask
// import semmle.code.java.frameworks.android.DeepLink
// import semmle.code.java.dataflow.DataFlow
// import semmle.code.java.dataflow.TaintTracking
// import semmle.code.java.dataflow.FlowSources
// import semmle.code.java.dataflow.FlowSteps
// import semmle.code.java.dataflow.ExternalFlow
//* select getData() method access in RouterActivity
// from AndroidComponent andComp, MethodAccess ma
// where
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getAnActionElement()
// .getActionName() = "android.intent.action.VIEW" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getACategoryElement()
// .getCategoryName() = "android.intent.category.BROWSABLE" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getACategoryElement()
// .getCategoryName() = "android.intent.category.DEFAULT" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getAChild("data")
// .hasAttribute("scheme") and // make sure to check for 'android' prefix in real query
// ma.getMethod().hasName("getData") and
// //ma.getCompilationUnit().toString() = andComp.toString() // string is "RouterActivity"
// andComp.getFile() = ma.getFile()
// select ma, "getData usage related to deeplink"
// * play with taint/data
// class DeepLinkConfiguration extends TaintTracking::Configuration {
// DeepLinkConfiguration() { this = "DeepLinkConfiguration" }
// override predicate isSource(DataFlow::Node source) {
// exists(MethodAccess ma, AndroidComponent andComp |
// ma.getMethod().hasName("getData") and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getAnActionElement()
// .getActionName() = "android.intent.action.VIEW" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getACategoryElement()
// .getCategoryName() = "android.intent.category.BROWSABLE" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getACategoryElement()
// .getCategoryName() = "android.intent.category.DEFAULT" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getAChild("data")
// .hasAttribute("scheme") and
// andComp.getFile() = ma.getFile() and
// source.asExpr() = ma
// )
// }
// override predicate isSink(DataFlow::Node sink) {
// exists(Variable v | v.hasName("currentUrl") and sink.asExpr() = v.getAnAccess())
// }
// }
// from DataFlow::Node src, DataFlow::Node sink, DeepLinkConfiguration config
// where config.hasFlow(src, sink)
// select src, "This environment variable constructs a URL $@.", sink, "here"
// * Intent experimentation:
//from
// AndroidComponent andComp, MethodAccess ma, StartActivityIntentStep startActIntStep,
// DataFlow::Node n1, DataFlow::Node n2
// where
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getAnActionElement()
// .getActionName() = "android.intent.action.VIEW" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getACategoryElement()
// .getCategoryName() = "android.intent.category.BROWSABLE" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getACategoryElement()
// .getCategoryName() = "android.intent.category.DEFAULT" and
// andComp
// .getAndroidComponentXmlElement()
// .getAnIntentFilterElement()
// .getAChild("data")
// .hasAttribute("scheme") and // make sure to check for 'android' prefix in real query
// //ma.getMethod().hasName("getData") and
// //andComp.getFile() = ma.getFile() and
// //n1.asExpr() = ma and
// //n1.asExpr() = ma and
// andComp.getAnAnnotation() = n1.asExpr() and
// startActIntStep.step(n1, n2)
// select n1, "deeplink"
// * experiment with StartActivityIntentStep
// from StartServiceIntentStep startServiceIntStep, DataFlow::Node n1, DataFlow::Node n2
// where startServiceIntStep.step(n1, n2)
// select n2, "placeholder"
// * experiment with taint-tracking
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.frameworks.android.DeepLink
import semmle.code.java.frameworks.android.Intent
import semmle.code.java.frameworks.android.Android
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.FlowSteps
import semmle.code.java.dataflow.FlowSources
import semmle.code.java.dataflow.ExternalFlow
import semmle.code.xml.AndroidManifest
import semmle.code.java.dataflow.TaintTracking
from StartServiceIntentStep startServiceIntStep, DataFlow::Node n1, DataFlow::Node n2
where startServiceIntStep.step(n1, n2)
select n2, "placeholder"
class MyTaintTrackingConfiguration extends TaintTracking::Configuration {
MyTaintTrackingConfiguration() { this = "MyTaintTrackingConfiguration" }
override predicate isSource(DataFlow::Node source) {
// exists(AndroidActivityXmlElement andActXmlElem |
// andActXmlElem.hasDeepLink() and
// source.asExpr() instanceof TypeActivity
// )
source instanceof RemoteFlowSource and //AndroidIntentInput
exists(AndroidComponent andComp |
andComp.getAndroidComponentXmlElement().(AndroidActivityXmlElement).hasDeepLink() and
source.asExpr().getFile() = andComp.getFile() // ! ugly, see if better way to do this
)
}
override predicate isSink(DataFlow::Node sink) {
exists(MethodAccess m |
m.getMethod().hasName("getIntent") and
sink.asExpr() = m
)
}
}
from DataFlow::Node src, DataFlow::Node sink, MyTaintTrackingConfiguration config
where config.hasFlow(src, sink)
select src, "This environment variable constructs a URL $@.", sink, "here"

View File

@@ -13,11 +13,9 @@
import java
import semmle.code.xml.AndroidManifest
// from AndroidActivityXmlElement actXmlElement
// where
// actXmlElement.hasDeepLink() and
// not actXmlElement.getFile().(AndroidManifestXmlFile).isInBuildDirectory()
// select actXmlElement, "A deeplink is used here."
from MethodAccess ma
where ma.getMethod().hasName("parseUri")
select ma, "parseUri access"
// simple query for testing and MRVA results
from AndroidActivityXmlElement actXmlElement
where
actXmlElement.hasDeepLink() and
not actXmlElement.getFile().(AndroidManifestXmlFile).isInBuildDirectory()
select actXmlElement, "A deeplink is used here."