mirror of
https://github.com/github/codeql.git
synced 2025-12-24 04:36:35 +01:00
resolve merge conflict
This commit is contained in:
committed by
Tony Torralba
parent
d07babe3c5
commit
47fcbdd4b4
@@ -1316,23 +1316,6 @@ 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
|
||||
)
|
||||
// ! e.g. use above in below code in `StartActivityIntentStep` in Intent.qll
|
||||
// argType.getName().matches("Class<%>") and
|
||||
// newIntent.getArgumentByType(argType).getType().(ParameterizedType).getATypeArgument() =
|
||||
// getIntent.getReceiverType() and
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a type argument provided to the constructor of this class instance creation expression.
|
||||
*
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
/** Provides classes and predicates to reason about deep links in Android. */
|
||||
|
||||
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.Android
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
//private import semmle.code.java.dataflow.DataFlow2
|
||||
private import semmle.code.java.dataflow.FlowSteps
|
||||
//private import semmle.code.java.dataflow.FlowSources
|
||||
//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.
|
||||
// ! and clean-up comments, etc. in below in general...
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
// ! experimental - make a DeepLink step that combine Activity, Service, Receiver, etc.
|
||||
private class DeepLinkIntentStep extends AdditionalValueStep {
|
||||
// DeepLinkIntentStep() {
|
||||
// this instanceof StartActivityIntentStep or
|
||||
// this instanceof SendBroadcastReceiverIntentStep or
|
||||
// this instanceof StartServiceIntentStep
|
||||
// }
|
||||
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
// ! simplify below
|
||||
(
|
||||
exists(StartServiceIntentStep startServiceIntentStep | startServiceIntentStep.step(n1, n2))
|
||||
or
|
||||
exists(SendBroadcastReceiverIntentStep sendBroadcastIntentStep |
|
||||
sendBroadcastIntentStep.step(n1, n2)
|
||||
)
|
||||
or
|
||||
exists(StartActivityIntentStep startActivityIntentStep | startActivityIntentStep.step(n1, n2))
|
||||
) and
|
||||
exists(AndroidComponent andComp |
|
||||
andComp.getAndroidComponentXmlElement().(AndroidActivityXmlElement).hasDeepLink() and
|
||||
n1.asExpr().getFile() = andComp.getFile() // ! see if better way to do this
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// // ! experimentation with global flow issue - REMOVE
|
||||
// /**
|
||||
// * A value-preserving step from the Intent variable
|
||||
// * the `Intent` Parameter in the `startActivity`.
|
||||
// */
|
||||
// class IntentVariableToStartActivityStep extends AdditionalValueStep {
|
||||
// override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
// exists(
|
||||
// MethodAccess startActivity, Variable intentTypeTest, DataFlow2::Node source,
|
||||
// DataFlow2::Node sink //ClassInstanceExpr intentTypeTest |
|
||||
// |
|
||||
// (
|
||||
// startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) or
|
||||
// startActivity.getMethod().overrides*(any(ActivityStartActivityMethod m))
|
||||
// ) and
|
||||
// intentTypeTest.getType() instanceof TypeIntent and // Variable
|
||||
// //intentTypeTest.getConstructedType() instanceof TypeIntent and // ClassInstanceExpr
|
||||
// startActivity.getFile().getBaseName() = "MainActivity.java" and // ! REMOVE - for testing only
|
||||
// //exists(StartComponentConfiguration cfg | cfg.hasFlow(source, sink)) and // GLOBAL FLOW ATTEMPT
|
||||
// DataFlow::localExprFlow(intentTypeTest.getInitializer(), startActivity.getArgument(0)) and // Variable - gives 5 results - misses the 1st ProfileActivity result since no variable with that one
|
||||
// //DataFlow::localExprFlow(intentTypeTest, startActivity.getArgument(0)) and // ClassInstanceExpr
|
||||
// n1.asExpr() = intentTypeTest.getInitializer() and // Variable
|
||||
// //n1.asExpr() = intentTypeTest and // ClassInstanceExpr
|
||||
// n2.asExpr() = startActivity.getArgument(0) // ! switch to getStartActivityIntentArg(startActivity)
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// ! rename?
|
||||
// ! below works as intended when run by itself (see latest query in AndroidDeeplinks_RemoteSources.ql),
|
||||
// ! but not when combined with existing flow steps (non-monotonic recursion)
|
||||
// ! need to figure out how to combine, or wrap all in global flow?
|
||||
class StartComponentConfiguration extends DataFlow::Configuration {
|
||||
StartComponentConfiguration() { this = "StartComponentConfiguration" }
|
||||
|
||||
// Override `isSource` and `isSink`.
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(ClassInstanceExpr classInstanceExpr |
|
||||
classInstanceExpr.getConstructedType() instanceof TypeIntent and
|
||||
source.asExpr() = classInstanceExpr
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess startActivity |
|
||||
// ! need to handle for all components, not just Activity
|
||||
(
|
||||
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) or
|
||||
startActivity.getMethod().overrides*(any(ActivityStartActivityMethod m))
|
||||
) and
|
||||
sink.asExpr() = startActivity.getArgument(0)
|
||||
)
|
||||
}
|
||||
// Optionally override `isBarrier`.
|
||||
// Optionally override `isAdditionalFlowStep`.
|
||||
// Then, to query whether there is flow between some `source` and `sink`,
|
||||
// write
|
||||
//
|
||||
// ```ql
|
||||
// exists(MyAnalysisConfiguration cfg | cfg.hasFlow(source, sink))
|
||||
// ```
|
||||
}
|
||||
|
||||
/* ********************* INTENT METHODS, E.G. parseUri, getData, getExtras, etc. ********************* */
|
||||
/*
|
||||
* Below is a Draft/Test of modelling `Intent.parseUri`, `Intent.getData`,
|
||||
* and `Intent.getExtras` methods
|
||||
*/
|
||||
|
||||
// ! Check if can use pre-existing Synthetic Field.
|
||||
/**
|
||||
* The method `Intent.get%Extra` or `Intent.getExtras`.
|
||||
*/
|
||||
class AndroidGetExtrasMethod extends Method {
|
||||
AndroidGetExtrasMethod() {
|
||||
this.getName().matches("get%Extra%") and
|
||||
this.getDeclaringType() instanceof TypeIntent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `Intent.getData`
|
||||
*/
|
||||
class AndroidGetDataMethod extends Method {
|
||||
AndroidGetDataMethod() {
|
||||
this.hasName("getData") and this.getDeclaringType() instanceof TypeIntent
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `Intent.parseUri`
|
||||
*/
|
||||
class AndroidParseUriMethod extends Method {
|
||||
AndroidParseUriMethod() {
|
||||
// ! Note to self: getIntent for older versions before deprecation to parseUri
|
||||
(this.hasName("parseUri") or this.hasName("getIntent")) and
|
||||
this.getDeclaringType() instanceof TypeIntent
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
import java
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
//private import semmle.code.java.dataflow.DataFlow2
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
private import semmle.code.java.dataflow.FlowSteps
|
||||
private import semmle.code.java.frameworks.android.DeepLink
|
||||
|
||||
// ! Remember to add 'private' annotation as needed to new classes/predicates below.
|
||||
// ! and clean-up comments, etc. in below in general...
|
||||
// ! and clean-up comments, etc. in below in general before marking as ready-for-review.
|
||||
/**
|
||||
* The class `android.content.Intent`.
|
||||
*/
|
||||
@@ -68,31 +66,18 @@ class AndroidReceiveIntentMethod extends Method {
|
||||
}
|
||||
}
|
||||
|
||||
// ! confirm if peekService should be modelled since it takes an Intent as a parameter
|
||||
// ! not sure if I like the name of the below class, but
|
||||
// ! trying to be consistent with `AndroidReceiveIntentMethod`
|
||||
// ! and `AndroidGetIntentMethod`...
|
||||
/**
|
||||
* 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`
|
||||
* A method of type Service that receives an Intent.
|
||||
* 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
|
||||
@@ -112,30 +97,22 @@ class AndroidServiceIntentMethod extends Method {
|
||||
}
|
||||
|
||||
/**
|
||||
* The method `Context.startActivity` or `startActivities`.
|
||||
* The method `Context.startActivity`, `Context.startActivities`,
|
||||
* `Activity.startActivity`,`Activity.startActivities`,
|
||||
* `Activity.startActivityForResult`, `Activity.startActivityIfNeeded`,
|
||||
* `Activity.startNextMatchingActivity`, `Activity.startActivityFromChild`,
|
||||
* or `Activity.startActivityFromFragment`.
|
||||
*/
|
||||
class ContextStartActivityMethod extends Method {
|
||||
ContextStartActivityMethod() {
|
||||
(this.hasName("startActivity") or this.hasName("startActivities")) and
|
||||
this.getDeclaringType() instanceof TypeContext
|
||||
}
|
||||
}
|
||||
|
||||
// ! maybe reword below QLDoc?
|
||||
/**
|
||||
* The method `Activity.startActivity`,`startActivities`,
|
||||
* `startActivityForResult`, `startActivityIfNeeded`,
|
||||
* `startNextMatchingActivity`, `startActivityFromChild`,
|
||||
* or `startActivityFromFragment`.
|
||||
*/
|
||||
class ActivityStartActivityMethod extends Method {
|
||||
ActivityStartActivityMethod() {
|
||||
class StartActivityMethod extends Method {
|
||||
StartActivityMethod() {
|
||||
this.getName().matches("start%Activit%") and
|
||||
this.getDeclaringType() instanceof TypeActivity
|
||||
(
|
||||
this.getDeclaringType() instanceof TypeContext or
|
||||
this.getDeclaringType() instanceof TypeActivity
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ! maybe reword below QLDoc?
|
||||
/**
|
||||
* The method `Context.sendBroadcast`, `sendBroadcastAsUser`,
|
||||
* `sendOrderedBroadcast`, `sendOrderedBroadcastAsUser`,
|
||||
@@ -143,30 +120,25 @@ class ActivityStartActivityMethod extends Method {
|
||||
* `sendStickyOrderedBroadcast`, `sendStickyOrderedBroadcastAsUser`,
|
||||
* or `sendBroadcastWithMultiplePermissions`.
|
||||
*/
|
||||
class ContextSendBroadcastMethod extends Method {
|
||||
ContextSendBroadcastMethod() {
|
||||
class SendBroadcastMethod extends Method {
|
||||
SendBroadcastMethod() {
|
||||
this.getName().matches("send%Broadcast%") and
|
||||
this.getDeclaringType() instanceof TypeContext
|
||||
}
|
||||
}
|
||||
|
||||
// ! update below QLDoc
|
||||
// ! remove reference from 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() {
|
||||
class StartServiceMethod extends Method {
|
||||
StartServiceMethod() {
|
||||
(
|
||||
// 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("start%Service") or
|
||||
this.getName().matches("bind%Service%")
|
||||
) and
|
||||
this.getDeclaringType() instanceof TypeContext
|
||||
@@ -282,7 +254,7 @@ class GrantWriteUriPermissionFlag extends GrantUriPermissionFlag {
|
||||
GrantWriteUriPermissionFlag() { this.hasName("FLAG_GRANT_WRITE_URI_PERMISSION") }
|
||||
}
|
||||
|
||||
// ! OLD VERSION
|
||||
// ! OLD VERSION - need to delete - keeping for now for reference
|
||||
// /**
|
||||
// * 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.
|
||||
@@ -301,46 +273,61 @@ class GrantWriteUriPermissionFlag extends GrantUriPermissionFlag {
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
/*
|
||||
* // ! TODO: create a parent class for the below three steps?
|
||||
* // ! e.g. something like the below?
|
||||
* // ! could put `getClassArgOfIntentConstructor` in parent class?
|
||||
*
|
||||
* // ! Also look into whether it's possible to reduce any code duplication
|
||||
* // ! across the three steps in general.
|
||||
* // class StartComponentIntentStep extends AdditionalValueStep { }
|
||||
*/
|
||||
|
||||
// The `android.Content.Intent` class has two constructors with an argument of type
|
||||
// `Class<?>`. One has the argument at position 1 and the other at position 3.
|
||||
// https://developer.android.com/reference/android/content/Intent#public-constructors
|
||||
private Argument getClassArgOfIntentConstructor(ClassInstanceExpr classInstanceExpr) {
|
||||
classInstanceExpr.getConstructedType() instanceof TypeIntent and
|
||||
if classInstanceExpr.getNumArgument() = 2
|
||||
then result = classInstanceExpr.getArgument(1)
|
||||
else result = classInstanceExpr.getArgument(3)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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) {
|
||||
private class StartActivityIntentStep extends AdditionalValueStep {
|
||||
// The `startActivityFromChild` and `startActivityFromFragment` methods have
|
||||
// an argument of type `Intent` at position 1, but the rest of the methods of
|
||||
// type `StartActivityMethod` have an argument of type `Intent` at position 0.
|
||||
private Argument getIntentArgOfStartActMethod(MethodAccess methodAccess) {
|
||||
methodAccess.getMethod().overrides*(any(StartActivityMethod m)) and
|
||||
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)
|
||||
methodAccess.getMethod().hasName("startActivityFromChild") or
|
||||
methodAccess.getMethod().hasName("startActivityFromFragment")
|
||||
then result = methodAccess.getArgument(1)
|
||||
else result = methodAccess.getArgument(0)
|
||||
}
|
||||
|
||||
// // The `android.Content.Intent` class has two constructors with an argument of type
|
||||
// // `Class<?>`. One has the argument at position 1 and the other at position 3.
|
||||
// // https://developer.android.com/reference/android/content/Intent#public-constructors
|
||||
// private Argument getClassArgOfIntentConstructor(ClassInstanceExpr classInstanceExpr) {
|
||||
// classInstanceExpr.getConstructedType() instanceof TypeIntent and
|
||||
// if classInstanceExpr.getNumArgument() = 2
|
||||
// then result = classInstanceExpr.getArgument(1)
|
||||
// else result = classInstanceExpr.getArgument(3)
|
||||
// }
|
||||
override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
exists(MethodAccess startActivity, MethodAccess getIntent, ClassInstanceExpr newIntent |
|
||||
(
|
||||
// ! look for better way to handle the below
|
||||
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) or
|
||||
startActivity.getMethod().overrides*(any(ActivityStartActivityMethod m))
|
||||
) and
|
||||
startActivity.getMethod().overrides*(any(StartActivityMethod m)) and
|
||||
getIntent.getMethod().overrides*(any(AndroidGetIntentMethod m)) and
|
||||
newIntent.getConstructedType() instanceof TypeIntent and
|
||||
DataFlow::localExprFlow(newIntent, getStartActivityIntentArg(startActivity)) and
|
||||
getIntentConstructorClassArg(newIntent).getType().(ParameterizedType).getATypeArgument() =
|
||||
DataFlow::localExprFlow(newIntent, getIntentArgOfStartActMethod(startActivity)) and
|
||||
getClassArgOfIntentConstructor(newIntent).getType().(ParameterizedType).getATypeArgument() =
|
||||
getIntent.getReceiverType() and
|
||||
n1.asExpr() = getStartActivityIntentArg(startActivity) and
|
||||
n1.asExpr() = getIntentArgOfStartActMethod(startActivity) and
|
||||
n2.asExpr() = getIntent
|
||||
)
|
||||
}
|
||||
@@ -348,17 +335,17 @@ class StartActivityIntentStep extends AdditionalValueStep {
|
||||
|
||||
/**
|
||||
* A value-preserving step from the Intent argument of a `sendBroadcast` call to
|
||||
* the `Intent` Parameter in the `onStart` method of the BroadcastReceiver the
|
||||
* the `Intent` parameter in the `onReceive` method of the BroadcastReceiver the
|
||||
* Intent pointed to in its constructor.
|
||||
*/
|
||||
class SendBroadcastReceiverIntentStep extends AdditionalValueStep {
|
||||
private 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
|
||||
sendBroadcast.getMethod().overrides*(any(SendBroadcastMethod 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() =
|
||||
getClassArgOfIntentConstructor(newIntent).getType().(ParameterizedType).getATypeArgument() =
|
||||
onReceive.getDeclaringType() and
|
||||
n1.asExpr() = sendBroadcast.getArgument(0) and
|
||||
n2.asParameter() = onReceive.getParameter(1)
|
||||
@@ -366,20 +353,20 @@ class SendBroadcastReceiverIntentStep extends AdditionalValueStep {
|
||||
}
|
||||
}
|
||||
|
||||
// ! potentially update QLDoc (e.g. remove `onStart` reference)
|
||||
// ! potentially reword QLDoc
|
||||
/**
|
||||
* 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.
|
||||
* the `Intent` parameter in an `AndroidServiceIntentMethod` of the Service the
|
||||
* Intent pointed to in its constructor.
|
||||
*/
|
||||
class StartServiceIntentStep extends AdditionalValueStep {
|
||||
private 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
|
||||
startService.getMethod().overrides*(any(StartServiceMethod 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() =
|
||||
getClassArgOfIntentConstructor(newIntent).getType().(ParameterizedType).getATypeArgument() =
|
||||
serviceIntent.getDeclaringType() and
|
||||
n1.asExpr() = startService.getArgument(0) and
|
||||
n2.asParameter() = serviceIntent.getParameter(0)
|
||||
|
||||
50
java/ql/lib/semmle/code/java/security/DeepLink.qll
Normal file
50
java/ql/lib/semmle/code/java/security/DeepLink.qll
Normal file
@@ -0,0 +1,50 @@
|
||||
/** Provides classes and predicates to reason about deep links in Android. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.frameworks.android.Intent
|
||||
private import semmle.code.java.frameworks.android.Android
|
||||
private import semmle.code.java.dataflow.DataFlow
|
||||
private import semmle.code.java.dataflow.TaintTracking
|
||||
private import semmle.code.java.dataflow.FlowSteps
|
||||
private import semmle.code.xml.AndroidManifest
|
||||
|
||||
// ! Experimentation file
|
||||
// /**
|
||||
// * 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.
|
||||
// */
|
||||
// // ! experimental - make a DeepLink step that combine Activity, Service, Receiver, etc.
|
||||
// private class DeepLinkIntentStep extends AdditionalValueStep {
|
||||
// // DeepLinkIntentStep() {
|
||||
// // this instanceof StartActivityIntentStep or
|
||||
// // this instanceof SendBroadcastReceiverIntentStep or
|
||||
// // this instanceof StartServiceIntentStep
|
||||
// // }
|
||||
// override predicate step(DataFlow::Node n1, DataFlow::Node n2) {
|
||||
// // ! simplify below
|
||||
// (
|
||||
// exists(StartServiceIntentStep startServiceIntentStep | startServiceIntentStep.step(n1, n2))
|
||||
// or
|
||||
// exists(SendBroadcastReceiverIntentStep sendBroadcastIntentStep |
|
||||
// sendBroadcastIntentStep.step(n1, n2)
|
||||
// )
|
||||
// or
|
||||
// exists(StartActivityIntentStep startActivityIntentStep | startActivityIntentStep.step(n1, n2))
|
||||
// ) and
|
||||
// exists(AndroidComponent andComp |
|
||||
// andComp.getAndroidComponentXmlElement().(AndroidActivityXmlElement).hasDeepLink() and
|
||||
// n1.asExpr().getFile() = andComp.getFile() // ! see if better way to do this
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// ! experimental modelling of `parseUri`
|
||||
/**
|
||||
* The method `Intent.parseUri`
|
||||
*/
|
||||
class AndroidParseUriMethod extends Method {
|
||||
AndroidParseUriMethod() {
|
||||
// ! Note: getIntent for older versions before deprecation to parseUri
|
||||
(this.hasName("parseUri") or this.hasName("getIntent")) and
|
||||
this.getDeclaringType() instanceof TypeIntent
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @name Android deep links
|
||||
* @description Android deep links
|
||||
* @problem.severity recommendation
|
||||
* @security-severity 0.1
|
||||
* @id java/android/deeplinks
|
||||
* @tags security
|
||||
* external/cwe/cwe-939
|
||||
* @precision high
|
||||
*/
|
||||
|
||||
// ! REMOVE this file
|
||||
// * experiment with StartActivityIntentStep
|
||||
import java
|
||||
import semmle.code.xml.AndroidManifest
|
||||
|
||||
// import semmle.code.java.dataflow.DataFlow
|
||||
// from StartServiceIntentStep startServiceIntStep, DataFlow::Node n1, DataFlow::Node n2
|
||||
// where startServiceIntStep.step(n1, n2)
|
||||
// select n2, "placeholder"
|
||||
// * experiment with Global Flow
|
||||
// import java
|
||||
// import semmle.code.java.dataflow.TaintTracking
|
||||
// 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
|
||||
// class StartComponentConfiguration extends DataFlow::Configuration {
|
||||
// StartComponentConfiguration() { this = "StartComponentConfiguration" }
|
||||
// // Override `isSource` and `isSink`.
|
||||
// override predicate isSource(DataFlow::Node source) {
|
||||
// exists(ClassInstanceExpr classInstanceExpr |
|
||||
// classInstanceExpr.getConstructedType() instanceof TypeIntent and
|
||||
// source.asExpr() = classInstanceExpr
|
||||
// )
|
||||
// }
|
||||
// override predicate isSink(DataFlow::Node sink) {
|
||||
// exists(MethodAccess startActivity |
|
||||
// (
|
||||
// startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) or
|
||||
// startActivity.getMethod().overrides*(any(ActivityStartActivityMethod m))
|
||||
// ) and
|
||||
// sink.asExpr() = startActivity.getArgument(0)
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// from
|
||||
// DataFlow::Node src, DataFlow::Node sink, StartComponentConfiguration config,
|
||||
// where
|
||||
// config.hasFlow(src, sink) and
|
||||
// sink.asExpr().getFile().getBaseName() = "MainActivity.java" // ! just for faster testing, remove when done
|
||||
// select src, "This source flows to this $@.", sink, "sink"
|
||||
// * simple query as placeholder
|
||||
from AndroidActivityXmlElement actXmlElement
|
||||
where
|
||||
actXmlElement.hasDeepLink() and
|
||||
not actXmlElement.getFile().(AndroidManifestXmlFile).isInBuildDirectory()
|
||||
select actXmlElement, "A deeplink is used here."
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* @name Android deep links
|
||||
* @description Android deep links
|
||||
* @problem.severity recommendation
|
||||
* @security-severity 0.1
|
||||
* @id java/android/deeplinks
|
||||
* @tags security
|
||||
* external/cwe/cwe-939
|
||||
* @precision high
|
||||
*/
|
||||
|
||||
// * experiment with StartActivityIntentStep
|
||||
// import java
|
||||
// import semmle.code.java.frameworks.android.DeepLink
|
||||
// import semmle.code.java.dataflow.DataFlow
|
||||
// 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
|
||||
// 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"
|
||||
// * experiment with GLOBAL FLOW
|
||||
import java
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
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
|
||||
|
||||
class StartComponentConfiguration extends DataFlow::Configuration {
|
||||
StartComponentConfiguration() { this = "StartComponentConfiguration" }
|
||||
|
||||
// TODO: Override `isSource` and `isSink`.
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(ClassInstanceExpr classInstanceExpr |
|
||||
classInstanceExpr.getConstructedType() instanceof TypeIntent and
|
||||
source.asExpr() = classInstanceExpr
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(MethodAccess startActivity |
|
||||
(
|
||||
startActivity.getMethod().overrides*(any(ContextStartActivityMethod m)) or
|
||||
startActivity.getMethod().overrides*(any(ActivityStartActivityMethod m))
|
||||
) and
|
||||
sink.asExpr() = startActivity.getArgument(0)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Node src, DataFlow::Node sink, StartComponentConfiguration config
|
||||
where
|
||||
config.hasFlow(src, sink) and
|
||||
sink.asExpr().getFile().getBaseName() = "MainActivity.java" // ! just for faster testing, remove when done
|
||||
select src, "This source flows to this $@.", sink, "sink"
|
||||
@@ -14,6 +14,7 @@ import java
|
||||
import semmle.code.xml.AndroidManifest
|
||||
|
||||
// simple query for testing and MRVA results
|
||||
// ! REMOVE this file
|
||||
from AndroidActivityXmlElement actXmlElement
|
||||
where
|
||||
actXmlElement.hasDeepLink() and
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
// ! adding tests in `intent` directory instead for now
|
||||
public class Test {
|
||||
|
||||
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/google-android-9.0.0
|
||||
@@ -1,2 +0,0 @@
|
||||
import java
|
||||
import TestUtilities.InlineFlowTest
|
||||
@@ -10,7 +10,8 @@ public class TestStartComponentToIntent {
|
||||
return null;
|
||||
}
|
||||
|
||||
static void sink(Object sink) {}
|
||||
static void sink(Object sink) {
|
||||
}
|
||||
|
||||
public void testActivity(Context ctx) {
|
||||
Intent intent = new Intent(null, SomeActivity.class);
|
||||
@@ -26,19 +27,19 @@ public class TestStartComponentToIntent {
|
||||
}
|
||||
|
||||
// ! WIP
|
||||
public void testService(Context ctx) {
|
||||
public void testService(Context ctx) {
|
||||
Intent intent = new Intent(null, SomeService.class);
|
||||
intent.putExtra("data", (String) source());
|
||||
ctx.startService(intent);
|
||||
}
|
||||
|
||||
public void testBroadcastReceiver(Context ctx) {
|
||||
public void testBroadcastReceiver(Context ctx) {
|
||||
Intent intent = new Intent(null, SomeBroadcastReceiver.class);
|
||||
intent.putExtra("data", (String) source());
|
||||
ctx.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
static class SomeService extends Service {
|
||||
static class SomeService extends Service {
|
||||
|
||||
public void test() {
|
||||
// ! WIP
|
||||
@@ -46,7 +47,7 @@ public class TestStartComponentToIntent {
|
||||
}
|
||||
}
|
||||
|
||||
static class SomeBroadcastReceiver extends BroadcastReceiver {
|
||||
static class SomeBroadcastReceiver extends BroadcastReceiver {
|
||||
|
||||
public void test() {
|
||||
// ! WIP
|
||||
|
||||
Reference in New Issue
Block a user