|
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