|
1 | 1 | /**
|
2 | 2 | * @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. |
4 | 4 | * @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 |
7 | 7 | * @id java/android/implicitly-exported-component
|
8 | 8 | * @tags security
|
9 | 9 | * external/cwe/cwe-926
|
10 |
| - * @precision TODO after MRVA |
| 10 | + * @precision high |
11 | 11 | */
|
12 | 12 |
|
13 | 13 | import java
|
14 | 14 | import semmle.code.xml.AndroidManifest
|
15 | 15 |
|
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