mirror of
https://github.com/github/codeql.git
synced 2026-04-30 11:15:13 +02:00
resolve merge conflict
This commit is contained in:
committed by
Tony Torralba
parent
11ce910c38
commit
9947b32446
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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."
|
||||
|
||||
Reference in New Issue
Block a user