Skip to content

Commit eea1089

Browse files
Jami CogswellJami Cogswell
authored andcommitted
resolved merge conflict in AndroidManifest
1 parent 60921a0 commit eea1089

File tree

3 files changed

+86
-64
lines changed

3 files changed

+86
-64
lines changed

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ class AndroidApplicationXmlElement extends XmlElement {
6767
attr.getValue() = "true"
6868
)
6969
}
70+
71+
/** Holds if this component element has an attribute with the name `permission`. */
72+
predicate hasPermissionAttribute() { exists(this.getAttribute("permission")) }
7073
}
7174

7275
/**
@@ -170,6 +173,11 @@ class AndroidComponentXmlElement extends XmlElement {
170173
*/
171174
AndroidIntentFilterXmlElement getAnIntentFilterElement() { result = this.getAChild() }
172175

176+
/**
177+
* Holds if this component element has an `<intent-filter>` child element.
178+
*/
179+
predicate hasAnIntentFilterElement() { this.getAChild().hasName("intent-filter") }
180+
173181
/**
174182
* Gets the value of the `android:name` attribute of this component element.
175183
*/
@@ -220,6 +228,23 @@ class AndroidComponentXmlElement extends XmlElement {
220228
* Holds if the `android:exported` attribute of this component element is explicitly set to `false`.
221229
*/
222230
predicate isNotExported() { this.getExportedAttributeValue() = "false" }
231+
232+
/**
233+
* Holds if this component element has an `android:exported` attribute.
234+
*/
235+
predicate hasExportedAttribute() { this.hasAttribute("exported") }
236+
237+
/** Holds if this component element has an attribute with the name `permission`. */
238+
predicate hasPermissionAttribute() { exists(this.getAttribute("permission")) }
239+
240+
predicate isImplicitlyExported() {
241+
not this.hasExportedAttribute() and
242+
this.hasAnIntentFilterElement() and // Note: did not use getAnIntentFilterElement since don't need a return value
243+
not this.hasPermissionAttribute() and
244+
not this.getParent().(AndroidApplicationXmlElement).hasPermissionAttribute() and
245+
not this.getAnIntentFilterElement().hasLauncherCategoryElement() and
246+
not this.getFile().(AndroidManifestXmlFile).isInBuildDirectory()
247+
}
223248
}
224249

225250
/**
@@ -234,6 +259,19 @@ class AndroidIntentFilterXmlElement extends XmlElement {
234259
* Gets an `<action>` child element of this `<intent-filter>` element.
235260
*/
236261
AndroidActionXmlElement getAnActionElement() { result = this.getAChild() }
262+
263+
/**
264+
* Gets a `<category>` child element of this `<intent-filter>` element.
265+
*/
266+
AndroidCategoryXmlElement getACategoryElement() { result = this.getAChild("category") }
267+
268+
/**
269+
* Holds if this `<intent-filter>` element has a `<category>` child element
270+
* named "android.intent.category.LAUNCHER".
271+
*/
272+
predicate hasLauncherCategoryElement() {
273+
this.getACategoryElement().getAttributeValue("name") = "android.intent.category.LAUNCHER"
274+
}
237275
}
238276

239277
/**
@@ -257,3 +295,25 @@ class AndroidActionXmlElement extends XmlElement {
257295
)
258296
}
259297
}
298+
299+
/**
300+
* A `<category>` element in an Android manifest file.
301+
*/
302+
class AndroidCategoryXmlElement extends XMLElement {
303+
AndroidCategoryXmlElement() {
304+
this.getFile() instanceof AndroidManifestXmlFile and this.getName() = "category"
305+
}
306+
307+
/**
308+
* Gets the name of this category.
309+
*/
310+
string getCategoryName() {
311+
exists(XMLAttribute attr |
312+
attr = this.getAnAttribute() and
313+
attr.getNamespace().getPrefix() = "android" and
314+
attr.getName() = "name"
315+
|
316+
result = attr.getValue()
317+
)
318+
}
319+
}

java/ql/src/Security/CWE/CWE-926/ImplicitlyExportedAndroidComponent.qhelp

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,25 @@
44
<qhelp>
55

66
<overview>
7-
<p>TODO: Replace the following
8-
When a debugger is enabled it could allow for entry points in the application or reveal sensitive information.</p>
7+
<p>The Android manifest file defines configuration settings for Android applications.
8+
In this file, the <code>android:debuggable</code> attribute of the <code>application</code> element can be used to
9+
define whether or not the application can be debugged. When set to <code>true</code>, this attribute will allow the
10+
application to be debugged even when running on a device in user mode.</p>
11+
12+
<p>When a debugger is enabled it could allow for entry points in the application or reveal sensitive information.
13+
As a result, <code>android:debuggable</code> should only be enabled during development and should be disabled in
14+
production builds.</p>
915

1016
</overview>
1117
<recommendation>
1218

13-
<p>TODO: Replace the following
14-
In Android applications either set the <code>android:debuggable</code> attribute to <code>false</code>
19+
<p>In Android applications either set the <code>android:debuggable</code> attribute to <code>false</code>
1520
or do not include it in the manifest. The default value when not included is <code>false</code>.</p>
1621

1722
</recommendation>
1823
<example>
1924

20-
<p>TODO: Replace the following
21-
In the example below, the <code>android:debuggable</code> attribute is set to <code>true</code>.</p>
25+
<p>In the example below, the <code>android:debuggable</code> attribute is set to <code>true</code>.</p>
2226

2327
<!--<sample src="DebuggableTrue.xml" />-->
2428

@@ -30,9 +34,17 @@ In the example below, the <code>android:debuggable</code> attribute is set to <c
3034
<references>
3135

3236
<li>
33-
TODO: REPLACE LINKS. Android Developers:
37+
Android Developers:
38+
<a href="https://developer.android.com/guide/topics/manifest/manifest-intro">App Manifest Overview</a>.
39+
</li>
40+
<li>
41+
Android Developers:
3442
<a href="https://developer.android.com/guide/topics/manifest/application-element#debug">The android:debuggable attribute</a>.
3543
</li>
44+
<li>
45+
Android Developers:
46+
<a href="https://developer.android.com/studio/debug#enable-debug">Enable debugging</a>.
47+
</li>
3648

3749
</references>
3850
</qhelp>
Lines changed: 7 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,18 @@
11
/**
22
* @name Implicitly exported Android component
3-
* @description TODO after more background reading
3+
* @description An Android component with an '<intent-filter>' and no 'android:exported' attribute is implicitly exported. This can allow for improper access to the component and its data.
44
* @kind problem
5-
* @problem.severity warning (TODO: confirm after more background reading)
6-
* @security-severity 0.1 (TODO: run script)
5+
* @problem.severity warning
6+
* @security-severity 8.2
77
* @id java/android/implicitly-exported-component
88
* @tags security
99
* external/cwe/cwe-926
10-
* @precision TODO after MRVA
10+
* @precision high
1111
*/
1212

1313
import java
1414
import semmle.code.xml.AndroidManifest
1515

16-
// FIRST DRAFT
17-
// from AndroidComponentXmlElement compElem
18-
// where
19-
// not compElem.hasAttribute("exported") and
20-
// compElem.getAChild().hasName("intent-filter") and
21-
// not compElem.hasAttribute("permission") and
22-
// not compElem
23-
// .getAnIntentFilterElement()
24-
// .getAnActionElement()
25-
// .getActionName()
26-
// .matches("android.intent.action.MAIN") and // filter out anything that is android intent (e.g. don't just filter out MAIN) because I think those are fine (but need to look at docs to confirm)
27-
// //not compElem.getAnIntentFilterElement().getAnActionElement().getActionName() = "android.intent.category.LAUNCHER" and // I should add this as well, but above will techincally filter out since they always seem to occur together
28-
// not compElem.getFile().getRelativePath().matches("%build%") // switch to not isInBuildDirectory() once new predicate is merged into main
29-
// select compElem, "This component is implicitly exported."
30-
// SECOND DRAFT
31-
// from AndroidComponentXmlElement compElem
32-
// where
33-
// // Does NOT have `exported` attribute
34-
// not compElem.hasAttribute("exported") and
35-
// // and DOES have an intent-filter (DOUBLE-CHECK THIS CODE AND CHECK AGAINST OTHER VERSIONS THAT SEEMED TO WORK THE SAME)
36-
// compElem.getAChild().hasName("intent-filter") and // compElem.getAChild("intent-filter"); need hasComponent with exists(...) here?
37-
// // and does NOT have `permission` attribute
38-
// not compElem.hasAttribute("permission") and
39-
// // and is NOT in build directory (NOTE: switch to not isInBuildDirectory() once new predicate is merged into main)
40-
// not compElem.getFile().getRelativePath().matches("%build%") and
41-
// // and does NOT have a LAUNCHER category, see docs: https://developer.android.com/about/versions/12/behavior-changes-12#exported
42-
// // Constant Value: "android.intent.category.LAUNCHER" from https://developer.android.com/reference/android/content/Intent#CATEGORY_LAUNCHER
43-
// // I think beloew is actually too coarse because there can be multiple intent-filters in one component, so 2nd intent-filter without the launcher
44-
// // could maybe be an issue, e.g. https://github.com/microsoft/DynamicsWOM/blob/62c2dad4cbbd4496a55aa3f644336044105bb1c1/app/src/main/AndroidManifest.xml#L56-L66
45-
// not compElem.getAnIntentFilterElement().getAChild("category").getAttributeValue("name") =
46-
// "android.intent.category.LAUNCHER" // double-check this code (especially use of getAChild and pattern match with LAUNCHER (e.g. should I do .%LAUNCHER instead?--No, constant value per docs), etc.), and definitely need to add stuff to library for this; should use exists(...) here?
47-
// select compElem, "This component is implicitly exported."
48-
// THIRD DRAFT
49-
from AndroidComponentXmlElement compElem, AndroidApplicationXmlElement appElem
50-
where
51-
// Does NOT have `exported` attribute
52-
not compElem.hasAttribute("exported") and
53-
// and DOES have an intent-filter
54-
compElem.getAChild().hasName("intent-filter") and // compElem.getAChild("intent-filter")
55-
// and does NOT have `permission` attribute
56-
not compElem.hasAttribute("permission") and
57-
// and is NOT in build directory (NOTE: switch to not isInBuildDirectory() once new predicate is merged into main)
58-
not compElem.getFile().getRelativePath().matches("%build%") and
59-
// and does NOT have a LAUNCHER category, see docs: https://developer.android.com/about/versions/12/behavior-changes-12#exported
60-
// Constant Value: "android.intent.category.LAUNCHER" from https://developer.android.com/reference/android/content/Intent#CATEGORY_LAUNCHER
61-
// I think below is actually filtering out too much because there can be multiple intent-filters in one component, so 2nd intent-filter without the launcher
62-
// could maybe be an issue, e.g. https://github.com/microsoft/DynamicsWOM/blob/62c2dad4cbbd4496a55aa3f644336044105bb1c1/app/src/main/AndroidManifest.xml#L56-L66
63-
not compElem.getAnIntentFilterElement().getAChild("category").getAttributeValue("name") =
64-
"android.intent.category.LAUNCHER" and
65-
// and NO android:permission attribute in <application> element since that will be applied to the component even
66-
// if no `permission` attribute directly set on component per the docs:
67-
not appElem.hasAttribute("permission")
68-
select compElem, "This component is implicitly exported."
16+
from AndroidComponentXmlElement compElement
17+
where compElement.isImplicitlyExported()
18+
select compElement, "This component is implicitly exported."

0 commit comments

Comments
 (0)