Skip to content

Commit a85de2b

Browse files
authored
Merge pull request github#10865 from egregius313/egregius313/android-activity-alias
Java: Add library support for activity-alias elements in AndroidManifest.qll
2 parents 9b0163c + b6a59f0 commit a85de2b

File tree

11 files changed

+200
-11
lines changed

11 files changed

+200
-11
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Added support for Android Manifest `<activity-aliases>` elements in data flow sources.

java/ql/lib/semmle/code/java/frameworks/android/Android.qll

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ class AndroidComponent extends Class {
2626

2727
/** The XML element corresponding to this Android component. */
2828
AndroidComponentXmlElement getAndroidComponentXmlElement() {
29-
result.getResolvedComponentName() = this.getQualifiedName()
29+
// Find an element with an identifier matching the qualified name of the component.
30+
// Aliases have two identifiers (name and target), so check both identifiers (if present).
31+
exists(AndroidIdentifierXmlAttribute identifier |
32+
identifier = result.getAnAttribute() and
33+
result.getResolvedIdentifier(identifier) = this.getQualifiedName()
34+
)
3035
}
3136

3237
/** Holds if this Android component is configured as `exported` in an `AndroidManifest.xml` file. */
@@ -52,6 +57,12 @@ class ExportableAndroidComponent extends AndroidComponent {
5257
or
5358
this.hasIntentFilter() and
5459
not this.getAndroidComponentXmlElement().isNotExported()
60+
or
61+
exists(AndroidActivityAliasXmlElement e |
62+
e = this.getAndroidComponentXmlElement() and
63+
not e.isNotExported() and
64+
e.hasAnIntentFilterElement()
65+
)
5566
}
5667
}
5768

java/ql/lib/semmle/code/xml/AndroidManifest.qll

Lines changed: 64 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,42 @@ class AndroidApplicationXmlElement extends XmlElement {
129129
*/
130130
class AndroidActivityXmlElement extends AndroidComponentXmlElement {
131131
AndroidActivityXmlElement() { this.getName() = "activity" }
132+
133+
/**
134+
* Gets an `<activity-alias>` element aliasing the activity.
135+
*/
136+
AndroidActivityAliasXmlElement getAnAlias() {
137+
exists(AndroidActivityAliasXmlElement alias | this = alias.getTarget() | result = alias)
138+
}
139+
}
140+
141+
/**
142+
* An `<activity-alias>` element in an Android manifest file.
143+
*/
144+
class AndroidActivityAliasXmlElement extends AndroidComponentXmlElement {
145+
AndroidActivityAliasXmlElement() { this.getName() = "activity-alias" }
146+
147+
/**
148+
* Get and resolve the name of the target activity from the `android:targetActivity` attribute.
149+
*/
150+
string getResolvedTargetActivityName() {
151+
exists(AndroidXmlAttribute attr |
152+
attr = this.getAnAttribute() and attr.getName() = "targetActivity"
153+
|
154+
result = this.getResolvedIdentifier(attr)
155+
)
156+
}
157+
158+
/**
159+
* Gets the `<activity>` element referenced by the `android:targetActivity` attribute.
160+
*/
161+
AndroidActivityXmlElement getTarget() {
162+
exists(AndroidActivityXmlElement activity |
163+
activity.getResolvedComponentName() = this.getResolvedTargetActivityName()
164+
|
165+
result = activity
166+
)
167+
}
132168
}
133169

134170
/**
@@ -212,6 +248,13 @@ class AndroidPermissionXmlAttribute extends XmlAttribute {
212248
predicate isWrite() { this.getName() = "writePermission" }
213249
}
214250

251+
/**
252+
* The attribute `android:name` or `android:targetActivity`.
253+
*/
254+
class AndroidIdentifierXmlAttribute extends AndroidXmlAttribute {
255+
AndroidIdentifierXmlAttribute() { this.getName() = ["name", "targetActivity"] }
256+
}
257+
215258
/**
216259
* The `<path-permission`> element of a `<provider>` in an Android manifest file.
217260
*/
@@ -228,7 +271,7 @@ class AndroidPathPermissionXmlElement extends XmlElement {
228271
class AndroidComponentXmlElement extends XmlElement {
229272
AndroidComponentXmlElement() {
230273
this.getParent() instanceof AndroidApplicationXmlElement and
231-
this.getName().regexpMatch("(activity|service|receiver|provider)")
274+
this.getName().regexpMatch("(activity|activity-alias|service|receiver|provider)")
232275
}
233276

234277
/**
@@ -254,19 +297,30 @@ class AndroidComponentXmlElement extends XmlElement {
254297
)
255298
}
256299

300+
/**
301+
* Gets the value of an identifier attribute, and tries to resolve it into a fully qualified identifier.
302+
*/
303+
string getResolvedIdentifier(AndroidIdentifierXmlAttribute identifier) {
304+
exists(string name | name = identifier.getValue() |
305+
if name.matches(".%")
306+
then
307+
result =
308+
this.getParent()
309+
.(XmlElement)
310+
.getParent()
311+
.(AndroidManifestXmlElement)
312+
.getPackageAttributeValue() + name
313+
else result = name
314+
)
315+
}
316+
257317
/**
258318
* Gets the resolved value of the `android:name` attribute of this component element.
259319
*/
260320
string getResolvedComponentName() {
261-
if this.getComponentName().matches(".%")
262-
then
263-
result =
264-
this.getParent()
265-
.(XmlElement)
266-
.getParent()
267-
.(AndroidManifestXmlElement)
268-
.getPackageAttributeValue() + this.getComponentName()
269-
else result = this.getComponentName()
321+
exists(AndroidXmlAttribute attr | attr = this.getAnAttribute() and attr.getName() = "name" |
322+
result = this.getResolvedIdentifier(attr)
323+
)
270324
}
271325

272326
/**
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
package="com.example.myapplication">
5+
6+
<application
7+
android:allowBackup="false"
8+
android:dataExtractionRules="@xml/data_extraction_rules"
9+
android:fullBackupContent="@xml/backup_rules"
10+
android:icon="@mipmap/ic_launcher"
11+
android:label="@string/app_name"
12+
android:roundIcon="@mipmap/ic_launcher_round"
13+
android:supportsRtl="true"
14+
15+
android:theme="@style/Theme.MyApplication"
16+
tools:targetApi="31">
17+
18+
<activity
19+
android:name=".MainActivity"
20+
android:exported="true"
21+
android:label="@string/app_name"
22+
android:theme="@style/Theme.MyApplication.NoActionBar">
23+
<intent-filter>
24+
<action android:name="android.intent.action.MAIN" />
25+
26+
<category android:name="android.intent.category.LAUNCHER" />
27+
</intent-filter>
28+
</activity>
29+
30+
<activity
31+
android:name=".AnotherActivity"
32+
android:exported="true"
33+
android:label="@string/app_name"
34+
android:theme="@style/Theme.MyApplication.NoActionBar">
35+
</activity>
36+
37+
38+
<activity-alias
39+
android:name=".MainAlias"
40+
android:exported="true"
41+
android:label="@string/app_name"
42+
android:targetActivity=".MainActivity"></activity-alias>
43+
44+
<activity-alias
45+
android:name=".SecondAlias"
46+
android:exported="true"
47+
android:label="@string/app_name"
48+
android:targetActivity=".MainActivity"></activity-alias>
49+
50+
<activity-alias
51+
android:name=".AnotherAlias"
52+
android:exported="true"
53+
android:label="@string/app_name"
54+
android:targetActivity="com.example.myapplication.AnotherActivity"></activity-alias>
55+
<activity
56+
android:name=".ExampleActivity"
57+
android:exported="false"
58+
android:label="@string/app_name"
59+
></activity>
60+
61+
<activity-alias
62+
android:name=".ExampleAlias"
63+
android:exported="true"
64+
android:label="@string/app_name"
65+
android:targetActivity=".ExampleActivity">
66+
</activity-alias>
67+
68+
<activity
69+
android:name=".Example2Activity"
70+
android:exported="false"
71+
android:label="@string/app_name">
72+
</activity>
73+
74+
<activity-alias
75+
android:name=".Example2Alias"
76+
android:label="@string/app_name"
77+
android:targetActivity=".Example2Activity">
78+
<intent-filter>
79+
<action android:name="android.intent.action.MAIN"></action>
80+
<action android:name="android.intent.category.LAUNCHER"></action>
81+
</intent-filter>
82+
</activity-alias>
83+
</application>
84+
85+
</manifest>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.example.myapplication;
2+
3+
import android.app.Activity;
4+
5+
public class Example2Activity extends Activity {
6+
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.example.myapplication;
2+
3+
import android.app.Activity;
4+
5+
public class ExampleActivity extends Activity {
6+
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
| .AnotherAlias | .AnotherActivity |
2+
| .Example2Alias | .Example2Activity |
3+
| .ExampleAlias | .ExampleActivity |
4+
| .MainAlias | .MainActivity |
5+
| .SecondAlias | .MainActivity |
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import java
2+
import semmle.code.xml.AndroidManifest
3+
4+
from AndroidActivityAliasXmlElement alias
5+
select alias.getComponentName(), alias.getTarget().getComponentName()
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
| Example2Activity.java:5:14:5:29 | Example2Activity | AndroidManifest.xml:68:9:72:20 | activity |
2+
| Example2Activity.java:5:14:5:29 | Example2Activity | AndroidManifest.xml:74:9:82:26 | activity-alias |
3+
| ExampleActivity.java:5:14:5:28 | ExampleActivity | AndroidManifest.xml:55:9:59:25 | activity |
4+
| ExampleActivity.java:5:14:5:28 | ExampleActivity | AndroidManifest.xml:61:9:66:26 | activity-alias |
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import java
2+
import semmle.code.java.frameworks.android.Android
3+
4+
from ExportableAndroidComponent component
5+
where component.isExported()
6+
select component, component.getAndroidComponentXmlElement()

0 commit comments

Comments
 (0)