Merge pull request #10865 from egregius313/egregius313/android-activity-alias

Java: Add library support for activity-alias elements in AndroidManifest.qll
This commit is contained in:
Edward Minnix III
2022-12-13 11:52:01 -05:00
committed by GitHub
11 changed files with 200 additions and 11 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Added support for Android Manifest `<activity-aliases>` elements in data flow sources.

View File

@@ -26,7 +26,12 @@ class AndroidComponent extends Class {
/** The XML element corresponding to this Android component. */
AndroidComponentXmlElement getAndroidComponentXmlElement() {
result.getResolvedComponentName() = this.getQualifiedName()
// Find an element with an identifier matching the qualified name of the component.
// Aliases have two identifiers (name and target), so check both identifiers (if present).
exists(AndroidIdentifierXmlAttribute identifier |
identifier = result.getAnAttribute() and
result.getResolvedIdentifier(identifier) = this.getQualifiedName()
)
}
/** Holds if this Android component is configured as `exported` in an `AndroidManifest.xml` file. */
@@ -52,6 +57,12 @@ class ExportableAndroidComponent extends AndroidComponent {
or
this.hasIntentFilter() and
not this.getAndroidComponentXmlElement().isNotExported()
or
exists(AndroidActivityAliasXmlElement e |
e = this.getAndroidComponentXmlElement() and
not e.isNotExported() and
e.hasAnIntentFilterElement()
)
}
}

View File

@@ -129,6 +129,42 @@ class AndroidApplicationXmlElement extends XmlElement {
*/
class AndroidActivityXmlElement extends AndroidComponentXmlElement {
AndroidActivityXmlElement() { this.getName() = "activity" }
/**
* Gets an `<activity-alias>` element aliasing the activity.
*/
AndroidActivityAliasXmlElement getAnAlias() {
exists(AndroidActivityAliasXmlElement alias | this = alias.getTarget() | result = alias)
}
}
/**
* An `<activity-alias>` element in an Android manifest file.
*/
class AndroidActivityAliasXmlElement extends AndroidComponentXmlElement {
AndroidActivityAliasXmlElement() { this.getName() = "activity-alias" }
/**
* Get and resolve the name of the target activity from the `android:targetActivity` attribute.
*/
string getResolvedTargetActivityName() {
exists(AndroidXmlAttribute attr |
attr = this.getAnAttribute() and attr.getName() = "targetActivity"
|
result = this.getResolvedIdentifier(attr)
)
}
/**
* Gets the `<activity>` element referenced by the `android:targetActivity` attribute.
*/
AndroidActivityXmlElement getTarget() {
exists(AndroidActivityXmlElement activity |
activity.getResolvedComponentName() = this.getResolvedTargetActivityName()
|
result = activity
)
}
}
/**
@@ -212,6 +248,13 @@ class AndroidPermissionXmlAttribute extends XmlAttribute {
predicate isWrite() { this.getName() = "writePermission" }
}
/**
* The attribute `android:name` or `android:targetActivity`.
*/
class AndroidIdentifierXmlAttribute extends AndroidXmlAttribute {
AndroidIdentifierXmlAttribute() { this.getName() = ["name", "targetActivity"] }
}
/**
* The `<path-permission`> element of a `<provider>` in an Android manifest file.
*/
@@ -228,7 +271,7 @@ class AndroidPathPermissionXmlElement extends XmlElement {
class AndroidComponentXmlElement extends XmlElement {
AndroidComponentXmlElement() {
this.getParent() instanceof AndroidApplicationXmlElement and
this.getName().regexpMatch("(activity|service|receiver|provider)")
this.getName().regexpMatch("(activity|activity-alias|service|receiver|provider)")
}
/**
@@ -254,19 +297,30 @@ class AndroidComponentXmlElement extends XmlElement {
)
}
/**
* Gets the value of an identifier attribute, and tries to resolve it into a fully qualified identifier.
*/
string getResolvedIdentifier(AndroidIdentifierXmlAttribute identifier) {
exists(string name | name = identifier.getValue() |
if name.matches(".%")
then
result =
this.getParent()
.(XmlElement)
.getParent()
.(AndroidManifestXmlElement)
.getPackageAttributeValue() + name
else result = name
)
}
/**
* Gets the resolved value of the `android:name` attribute of this component element.
*/
string getResolvedComponentName() {
if this.getComponentName().matches(".%")
then
result =
this.getParent()
.(XmlElement)
.getParent()
.(AndroidManifestXmlElement)
.getPackageAttributeValue() + this.getComponentName()
else result = this.getComponentName()
exists(AndroidXmlAttribute attr | attr = this.getAnAttribute() and attr.getName() = "name" |
result = this.getResolvedIdentifier(attr)
)
}
/**

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<application
android:allowBackup="false"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApplication.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".AnotherActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.MyApplication.NoActionBar">
</activity>
<activity-alias
android:name=".MainAlias"
android:exported="true"
android:label="@string/app_name"
android:targetActivity=".MainActivity"></activity-alias>
<activity-alias
android:name=".SecondAlias"
android:exported="true"
android:label="@string/app_name"
android:targetActivity=".MainActivity"></activity-alias>
<activity-alias
android:name=".AnotherAlias"
android:exported="true"
android:label="@string/app_name"
android:targetActivity="com.example.myapplication.AnotherActivity"></activity-alias>
<activity
android:name=".ExampleActivity"
android:exported="false"
android:label="@string/app_name"
></activity>
<activity-alias
android:name=".ExampleAlias"
android:exported="true"
android:label="@string/app_name"
android:targetActivity=".ExampleActivity">
</activity-alias>
<activity
android:name=".Example2Activity"
android:exported="false"
android:label="@string/app_name">
</activity>
<activity-alias
android:name=".Example2Alias"
android:label="@string/app_name"
android:targetActivity=".Example2Activity">
<intent-filter>
<action android:name="android.intent.action.MAIN"></action>
<action android:name="android.intent.category.LAUNCHER"></action>
</intent-filter>
</activity-alias>
</application>
</manifest>

View File

@@ -0,0 +1,7 @@
package com.example.myapplication;
import android.app.Activity;
public class Example2Activity extends Activity {
}

View File

@@ -0,0 +1,7 @@
package com.example.myapplication;
import android.app.Activity;
public class ExampleActivity extends Activity {
}

View File

@@ -0,0 +1,5 @@
| .AnotherAlias | .AnotherActivity |
| .Example2Alias | .Example2Activity |
| .ExampleAlias | .ExampleActivity |
| .MainAlias | .MainActivity |
| .SecondAlias | .MainActivity |

View File

@@ -0,0 +1,5 @@
import java
import semmle.code.xml.AndroidManifest
from AndroidActivityAliasXmlElement alias
select alias.getComponentName(), alias.getTarget().getComponentName()

View File

@@ -0,0 +1,4 @@
| Example2Activity.java:5:14:5:29 | Example2Activity | AndroidManifest.xml:68:9:72:20 | activity |
| Example2Activity.java:5:14:5:29 | Example2Activity | AndroidManifest.xml:74:9:82:26 | activity-alias |
| ExampleActivity.java:5:14:5:28 | ExampleActivity | AndroidManifest.xml:55:9:59:25 | activity |
| ExampleActivity.java:5:14:5:28 | ExampleActivity | AndroidManifest.xml:61:9:66:26 | activity-alias |

View File

@@ -0,0 +1,6 @@
import java
import semmle.code.java.frameworks.android.Android
from ExportableAndroidComponent component
where component.isExported()
select component, component.getAndroidComponentXmlElement()

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../../stubs/google-android-9.0.0/