Skip to content

Commit 3ea167c

Browse files
committed
Split ArbitraryApkInstallation file into 3 files
1 parent 2d1088e commit 3ea167c

File tree

3 files changed

+191
-184
lines changed

3 files changed

+191
-184
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/** Provide classes to reason about Android Intents that can install APKs. */
2+
3+
import java
4+
import semmle.code.java.frameworks.android.Intent
5+
import semmle.code.java.dataflow.DataFlow
6+
private import semmle.code.java.dataflow.ExternalFlow
7+
private import semmle.code.java.dataflow.FlowSources
8+
9+
/** A string literal that represents the MIME type for Android APKs. */
10+
class PackageArchiveMimeTypeLiteral extends StringLiteral {
11+
PackageArchiveMimeTypeLiteral() { this.getValue() = "application/vnd.android.package-archive" }
12+
}
13+
14+
/** The `android.content.Intent.ACTION_INSTALL_PACKAGE` constant. */
15+
class InstallPackageAction extends Expr {
16+
InstallPackageAction() {
17+
this.(StringLiteral).getValue() = "android.intent.action.INSTALL_PACKAGE"
18+
or
19+
exists(VarAccess va |
20+
va.getVariable().hasName("ACTION_INSTALL_PACKAGE") and
21+
va.getQualifier().getType() instanceof TypeIntent
22+
)
23+
}
24+
}
25+
26+
/** A method that sets the MIME type of an intent. */
27+
class SetTypeMethod extends Method {
28+
SetTypeMethod() {
29+
this.hasName(["setType", "setTypeAndNormalize"]) and
30+
this.getDeclaringType() instanceof TypeIntent
31+
}
32+
}
33+
34+
/** A method that sets the data URI and the MIME type of an intent. */
35+
class SetDataAndTypeMethod extends Method {
36+
SetDataAndTypeMethod() {
37+
this.hasName(["setDataAndType", "setDataAndTypeAndNormalize"]) and
38+
this.getDeclaringType() instanceof TypeIntent
39+
}
40+
}
41+
42+
/** A method that sets the data URI of an intent. */
43+
class SetDataMethod extends Method {
44+
SetDataMethod() {
45+
this.hasName(["setData", "setDataAndNormalize", "setDataAndType", "setDataAndTypeAndNormalize"]) and
46+
this.getDeclaringType() instanceof TypeIntent
47+
}
48+
}
49+
50+
/** A dataflow sink for the URI of an intent. */
51+
class SetDataSink extends DataFlow::ExprNode {
52+
SetDataSink() {
53+
exists(MethodAccess ma |
54+
this.getExpr() = ma.getQualifier() and
55+
ma.getMethod() instanceof SetDataMethod
56+
)
57+
}
58+
}
59+
60+
/** A method that generates a URI. */
61+
class UriConstructorMethod extends Method {
62+
UriConstructorMethod() {
63+
this.hasQualifiedName("android.net", "Uri", ["fromFile", "fromParts"]) or
64+
this.hasQualifiedName("androidx.core.content", "FileProvider", "getUriForFile")
65+
}
66+
}
67+
68+
/**
69+
* A dataflow source representing the URIs which an APK not controlled by the
70+
* application may come from. Including external storage and web URLs.
71+
*/
72+
class ExternalApkSource extends DataFlow::Node {
73+
ExternalApkSource() {
74+
sourceNode(this, "android-external-storage-dir") or
75+
this.asExpr().(MethodAccess).getMethod() instanceof UriConstructorMethod or
76+
this.asExpr().(StringLiteral).getValue().matches("file://%") or
77+
this instanceof RemoteFlowSource
78+
}
79+
}
80+
81+
/** The `setAction` method of the `android.content.Intent` class. */
82+
class SetActionMethod extends Method {
83+
SetActionMethod() {
84+
this.hasName("setAction") and
85+
this.getDeclaringType() instanceof TypeIntent
86+
}
87+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import java
2+
import semmle.code.java.dataflow.DataFlow
3+
import semmle.code.java.dataflow.TaintTracking2
4+
import semmle.code.java.dataflow.TaintTracking3
5+
private import semmle.code.java.security.ArbitraryApkInstallation
6+
7+
/**
8+
* A dataflow configuration for flow from an external source of an APK to the
9+
* `setData[AndType][AndNormalize]` method of an intent.
10+
*/
11+
class ApkConfiguration extends DataFlow::Configuration {
12+
ApkConfiguration() { this = "ApkConfiguration" }
13+
14+
override predicate isSource(DataFlow::Node node) { node instanceof ExternalApkSource }
15+
16+
override predicate isSink(DataFlow::Node node) {
17+
exists(MethodAccess ma |
18+
ma.getMethod() instanceof SetDataMethod and
19+
ma.getArgument(0) = node.asExpr() and
20+
(
21+
any(PackageArchiveMimeTypeConfiguration c).hasFlowToExpr(ma.getQualifier())
22+
or
23+
any(InstallPackageActionConfiguration c).hasFlowToExpr(ma.getQualifier())
24+
)
25+
)
26+
}
27+
}
28+
29+
/**
30+
* A dataflow configuration tracking the flow from the `android.content.Intent.ACTION_INSTALL_PACKAGE`
31+
* constant to either the constructor of an intent or the `setAction` method of an intent.
32+
*
33+
* This is used to track if an intent is used to install an APK.
34+
*/
35+
private class InstallPackageActionConfiguration extends TaintTracking3::Configuration {
36+
InstallPackageActionConfiguration() { this = "InstallPackageActionConfiguration" }
37+
38+
override predicate isSource(DataFlow::Node source) {
39+
source.asExpr() instanceof InstallPackageAction
40+
}
41+
42+
override predicate isAdditionalTaintStep(
43+
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
44+
DataFlow::FlowState state2
45+
) {
46+
state1 instanceof DataFlow::FlowStateEmpty and
47+
state2 = "hasPackageInstallAction" and
48+
(
49+
exists(ConstructorCall cc |
50+
cc.getConstructedType() instanceof TypeIntent and
51+
node1.asExpr() = cc.getArgument(0) and
52+
node1.asExpr().getType() instanceof TypeString and
53+
node2.asExpr() = cc
54+
)
55+
or
56+
exists(MethodAccess ma |
57+
ma.getMethod() instanceof SetActionMethod and
58+
node1.asExpr() = ma.getArgument(0) and
59+
node2.asExpr() = ma.getQualifier()
60+
)
61+
)
62+
}
63+
64+
override predicate isSink(DataFlow::Node node, DataFlow::FlowState state) {
65+
state = "hasPackageInstallAction" and node.asExpr().getType() instanceof TypeIntent
66+
}
67+
}
68+
69+
/**
70+
* A dataflow configuration tracking the flow of the Android APK MIME type to
71+
* the `setType` or `setTypeAndNormalize` method of an intent, followed by a call
72+
* to `setData[AndType][AndNormalize]`.
73+
*/
74+
private class PackageArchiveMimeTypeConfiguration extends TaintTracking2::Configuration {
75+
PackageArchiveMimeTypeConfiguration() { this = "PackageArchiveMimeTypeConfiguration" }
76+
77+
override predicate isSource(DataFlow::Node node) {
78+
node.asExpr() instanceof PackageArchiveMimeTypeLiteral
79+
}
80+
81+
override predicate isAdditionalTaintStep(
82+
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
83+
DataFlow::FlowState state2
84+
) {
85+
state1 instanceof DataFlow::FlowStateEmpty and
86+
state2 = "typeSet" and
87+
exists(MethodAccess ma |
88+
ma.getQualifier() = node2.asExpr() and
89+
(
90+
ma.getMethod() instanceof SetTypeMethod and
91+
ma.getArgument(0) = node1.asExpr()
92+
or
93+
ma.getMethod() instanceof SetDataAndTypeMethod and
94+
ma.getArgument(1) = node1.asExpr()
95+
)
96+
)
97+
}
98+
99+
override predicate isSink(DataFlow::Node node, DataFlow::FlowState state) {
100+
state = "typeSet" and
101+
node instanceof SetDataSink
102+
}
103+
}

java/ql/src/Security/CWE/CWE-094/ArbitraryAPKInstallation.ql

Lines changed: 1 addition & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -11,192 +11,9 @@
1111
*/
1212

1313
import java
14-
import semmle.code.java.frameworks.android.Intent
15-
import semmle.code.java.dataflow.DataFlow
16-
import semmle.code.java.dataflow.TaintTracking2
17-
import semmle.code.java.dataflow.TaintTracking3
18-
import semmle.code.java.dataflow.FlowSources
19-
private import semmle.code.java.dataflow.ExternalFlow
14+
import semmle.code.java.security.ArbitraryApkInstallationQuery
2015
import DataFlow::PathGraph
2116

22-
/** A string literal that represents the MIME type for Android APKs. */
23-
class PackageArchiveMimeTypeLiteral extends StringLiteral {
24-
PackageArchiveMimeTypeLiteral() { this.getValue() = "application/vnd.android.package-archive" }
25-
}
26-
27-
/** The `android.content.Intent.ACTION_INSTALL_PACKAGE` constant. */
28-
class InstallPackageAction extends Expr {
29-
InstallPackageAction() {
30-
this.(StringLiteral).getValue() = "android.intent.action.INSTALL_PACKAGE"
31-
or
32-
exists(VarAccess va |
33-
va.getVariable().hasName("ACTION_INSTALL_PACKAGE") and
34-
va.getQualifier().getType() instanceof TypeIntent
35-
)
36-
}
37-
}
38-
39-
/** A method that sets the MIME type of an intent. */
40-
class SetTypeMethod extends Method {
41-
SetTypeMethod() {
42-
this.hasName(["setType", "setTypeAndNormalize"]) and
43-
this.getDeclaringType() instanceof TypeIntent
44-
}
45-
}
46-
47-
/** A method that sets the data URI and the MIME type of an intent. */
48-
class SetDataAndTypeMethod extends Method {
49-
SetDataAndTypeMethod() {
50-
this.hasName(["setDataAndType", "setDataAndTypeAndNormalize"]) and
51-
this.getDeclaringType() instanceof TypeIntent
52-
}
53-
}
54-
55-
/** A method that sets the data URI of an intent. */
56-
class SetDataMethod extends Method {
57-
SetDataMethod() {
58-
this.hasName(["setData", "setDataAndNormalize", "setDataAndType", "setDataAndTypeAndNormalize"]) and
59-
this.getDeclaringType() instanceof TypeIntent
60-
}
61-
}
62-
63-
/** A dataflow sink for the URI of an intent. */
64-
class SetDataSink extends DataFlow::ExprNode {
65-
SetDataSink() {
66-
exists(MethodAccess ma |
67-
this.getExpr() = ma.getQualifier() and
68-
ma.getMethod() instanceof SetDataMethod
69-
)
70-
}
71-
}
72-
73-
/** A method that generates a URI. */
74-
class UriConstructorMethod extends Method {
75-
UriConstructorMethod() {
76-
this.hasQualifiedName("android.net", "Uri", ["fromFile", "fromParts"]) or
77-
this.hasQualifiedName("androidx.core.content", "FileProvider", "getUriForFile")
78-
}
79-
}
80-
81-
/**
82-
* A dataflow source representing the URIs which an APK not controlled by the
83-
* application may come from. Including external storage and web URLs.
84-
*/
85-
class ExternalApkSource extends DataFlow::Node {
86-
ExternalApkSource() {
87-
sourceNode(this, "android-external-storage-dir") or
88-
this.asExpr().(MethodAccess).getMethod() instanceof UriConstructorMethod or
89-
this.asExpr().(StringLiteral).getValue().matches("file://%") or
90-
this instanceof RemoteFlowSource
91-
}
92-
}
93-
94-
/**
95-
* A dataflow configuration for flow from an external source of an APK to the
96-
* `setData[AndType][AndNormalize]` method of an intent.
97-
*/
98-
class ApkConfiguration extends DataFlow::Configuration {
99-
ApkConfiguration() { this = "ApkConfiguration" }
100-
101-
override predicate isSource(DataFlow::Node node) { node instanceof ExternalApkSource }
102-
103-
override predicate isSink(DataFlow::Node node) {
104-
exists(MethodAccess ma |
105-
ma.getMethod() instanceof SetDataMethod and
106-
ma.getArgument(0) = node.asExpr() and
107-
(
108-
any(PackageArchiveMimeTypeConfiguration c).hasFlowToExpr(ma.getQualifier())
109-
or
110-
any(InstallPackageActionConfiguration c).hasFlowToExpr(ma.getQualifier())
111-
)
112-
)
113-
}
114-
}
115-
116-
/** The `setAction` method of the `android.content.Intent` class. */
117-
class SetActionMethod extends Method {
118-
SetActionMethod() {
119-
this.hasName("setAction") and
120-
this.getDeclaringType() instanceof TypeIntent
121-
}
122-
}
123-
124-
/**
125-
* A dataflow configuration tracking the flow from the `android.content.Intent.ACTION_INSTALL_PACKAGE`
126-
* constant to either the constructor of an intent or the `setAction` method of an intent.
127-
*
128-
* This is used to track if an intent is used to install an APK.
129-
*/
130-
private class InstallPackageActionConfiguration extends TaintTracking3::Configuration {
131-
InstallPackageActionConfiguration() { this = "InstallPackageActionConfiguration" }
132-
133-
override predicate isSource(DataFlow::Node source) {
134-
source.asExpr() instanceof InstallPackageAction
135-
}
136-
137-
override predicate isAdditionalTaintStep(
138-
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
139-
DataFlow::FlowState state2
140-
) {
141-
state1 instanceof DataFlow::FlowStateEmpty and
142-
state2 = "hasPackageInstallAction" and
143-
(
144-
exists(ConstructorCall cc |
145-
cc.getConstructedType() instanceof TypeIntent and
146-
node1.asExpr() = cc.getArgument(0) and
147-
node1.asExpr().getType() instanceof TypeString and
148-
node2.asExpr() = cc
149-
)
150-
or
151-
exists(MethodAccess ma |
152-
ma.getMethod() instanceof SetActionMethod and
153-
node1.asExpr() = ma.getArgument(0) and
154-
node2.asExpr() = ma.getQualifier()
155-
)
156-
)
157-
}
158-
159-
override predicate isSink(DataFlow::Node node, DataFlow::FlowState state) {
160-
state = "hasPackageInstallAction" and node.asExpr().getType() instanceof TypeIntent
161-
}
162-
}
163-
164-
/**
165-
* A dataflow configuration tracking the flow of the Android APK MIME type to
166-
* the `setType` or `setTypeAndNormalize` method of an intent, followed by a call
167-
* to `setData[AndType][AndNormalize]`.
168-
*/
169-
private class PackageArchiveMimeTypeConfiguration extends TaintTracking2::Configuration {
170-
PackageArchiveMimeTypeConfiguration() { this = "PackageArchiveMimeTypeConfiguration" }
171-
172-
override predicate isSource(DataFlow::Node node) {
173-
node.asExpr() instanceof PackageArchiveMimeTypeLiteral
174-
}
175-
176-
override predicate isAdditionalTaintStep(
177-
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
178-
DataFlow::FlowState state2
179-
) {
180-
state1 instanceof DataFlow::FlowStateEmpty and
181-
state2 = "typeSet" and
182-
exists(MethodAccess ma |
183-
ma.getQualifier() = node2.asExpr() and
184-
(
185-
ma.getMethod() instanceof SetTypeMethod and
186-
ma.getArgument(0) = node1.asExpr()
187-
or
188-
ma.getMethod() instanceof SetDataAndTypeMethod and
189-
ma.getArgument(1) = node1.asExpr()
190-
)
191-
)
192-
}
193-
194-
override predicate isSink(DataFlow::Node node, DataFlow::FlowState state) {
195-
state = "typeSet" and
196-
node instanceof SetDataSink
197-
}
198-
}
199-
20017
from DataFlow::PathNode source, DataFlow::PathNode sink, ApkConfiguration config
20118
where config.hasFlowPath(source, sink)
20219
select sink.getNode(), source, sink, "Arbitrary Android APK installation."

0 commit comments

Comments
 (0)