Skip to content

Commit 143920e

Browse files
Movee query logic to a qll file
1 parent c68a707 commit 143920e

File tree

2 files changed

+159
-155
lines changed

2 files changed

+159
-155
lines changed

java/ql/src/Security/CWE/CWE-927/SensitiveBroadcast.ql

Lines changed: 1 addition & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -12,163 +12,9 @@
1212
*/
1313

1414
import java
15-
import semmle.code.java.dataflow.DataFlow3
16-
import semmle.code.java.dataflow.TaintTracking
17-
import semmle.code.java.frameworks.android.Intent
18-
import semmle.code.java.security.SensitiveActions
15+
import semmle.code.java.security.AndroidSensitiveBroadcastQuery
1916
import DataFlow::PathGraph
2017

21-
/**
22-
* Gets regular expression for matching names of Android variables that indicate the value being held contains sensitive information.
23-
*/
24-
private string getAndroidSensitiveInfoRegex() { result = "(?i).*(email|phone|ticket).*" }
25-
26-
/**
27-
* Method call to pass information to the `Intent` object.
28-
*/
29-
class PutIntentExtraMethodAccess extends MethodAccess {
30-
PutIntentExtraMethodAccess() {
31-
(
32-
getMethod().getName().matches("put%Extra") or
33-
getMethod().hasName("putExtras")
34-
) and
35-
getMethod().getDeclaringType() instanceof TypeIntent
36-
}
37-
}
38-
39-
/**
40-
* Method call to pass information to the intent extra bundle object.
41-
*/
42-
class PutBundleExtraMethodAccess extends MethodAccess {
43-
PutBundleExtraMethodAccess() {
44-
getMethod().getName().regexpMatch("put\\w+") and
45-
getMethod().getDeclaringType().getASupertype*().hasQualifiedName("android.os", "BaseBundle")
46-
}
47-
}
48-
49-
/** Finds variables that hold sensitive information judging by their names. */
50-
class SensitiveInfoExpr extends Expr {
51-
SensitiveInfoExpr() {
52-
exists(Variable v | this = v.getAnAccess() |
53-
v.getName().regexpMatch([getCommonSensitiveInfoRegex(), getAndroidSensitiveInfoRegex()])
54-
)
55-
}
56-
}
57-
58-
/**
59-
* A method access of the `Context.sendBroadcast` family.
60-
*/
61-
class SendBroadcastMethodAccess extends MethodAccess {
62-
SendBroadcastMethodAccess() {
63-
this.getMethod().getDeclaringType() instanceof TypeContext and
64-
this.getMethod().getName().matches("send%Broadcast%")
65-
}
66-
}
67-
68-
private class NullArgFlowConfig extends DataFlow2::Configuration {
69-
NullArgFlowConfig() { this = "Flow configuration with a null argument" }
70-
71-
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof NullLiteral }
72-
73-
override predicate isSink(DataFlow::Node sink) {
74-
exists(SendBroadcastMethodAccess ma | sink.asExpr() = ma.getAnArgument())
75-
}
76-
}
77-
78-
private class EmptyArrayArgFlowConfig extends DataFlow3::Configuration {
79-
EmptyArrayArgFlowConfig() { this = "Flow configuration with an empty array argument" }
80-
81-
override predicate isSource(DataFlow::Node src) {
82-
src.asExpr().(ArrayCreationExpr).getFirstDimensionSize() = 0
83-
}
84-
85-
override predicate isSink(DataFlow::Node sink) {
86-
exists(SendBroadcastMethodAccess ma | sink.asExpr() = ma.getAnArgument())
87-
}
88-
}
89-
90-
/**
91-
* Holds if a `sendBroadcast` call doesn't specify receiver permission.
92-
*/
93-
predicate isSensitiveBroadcastSink(DataFlow::Node sink) {
94-
exists(SendBroadcastMethodAccess ma |
95-
sink.asExpr() = ma.getAnArgument() and
96-
(
97-
ma.getMethod().hasName("sendBroadcast") and
98-
(
99-
ma.getNumArgument() = 1 // sendBroadcast(Intent intent)
100-
or
101-
// sendBroadcast(Intent intent, String receiverPermission)
102-
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1))))
103-
)
104-
or
105-
ma.getMethod().hasName("sendBroadcastAsUser") and
106-
(
107-
ma.getNumArgument() = 2 or // sendBroadcastAsUser(Intent intent, UserHandle user)
108-
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2)))) // sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)
109-
)
110-
or
111-
ma.getMethod().hasName("sendBroadcastWithMultiplePermissions") and
112-
exists(EmptyArrayArgFlowConfig config |
113-
config.hasFlow(_, DataFlow::exprNode(ma.getArgument(1))) // sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions)
114-
)
115-
or
116-
// Method calls of `sendOrderedBroadcast` whose second argument is always `receiverPermission`
117-
ma.getMethod().hasName("sendOrderedBroadcast") and
118-
(
119-
// sendOrderedBroadcast(Intent intent, String receiverPermission) or sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
120-
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1)))) and
121-
ma.getNumArgument() <= 7
122-
or
123-
// sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
124-
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1)))) and
125-
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2)))) and
126-
ma.getNumArgument() = 8
127-
)
128-
or
129-
// Method call of `sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)`
130-
ma.getMethod().hasName("sendOrderedBroadcastAsUser") and
131-
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2))))
132-
)
133-
)
134-
}
135-
136-
/**
137-
* Taint configuration tracking flow from variables containing sensitive information to broadcast intents.
138-
*/
139-
class SensitiveBroadcastConfig extends TaintTracking::Configuration {
140-
SensitiveBroadcastConfig() { this = "Sensitive Broadcast Configuration" }
141-
142-
override predicate isSource(DataFlow::Node source) {
143-
source.asExpr() instanceof SensitiveInfoExpr
144-
}
145-
146-
override predicate isSink(DataFlow::Node sink) { isSensitiveBroadcastSink(sink) }
147-
148-
/**
149-
* Holds if there is an additional flow step from `PutIntentExtraMethodAccess` or `PutBundleExtraMethodAccess` that taints the `Intent` or its extras `Bundle`.
150-
*/
151-
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
152-
exists(PutIntentExtraMethodAccess pia |
153-
node1.asExpr() = pia.getAnArgument() and node2.asExpr() = pia.getQualifier()
154-
)
155-
or
156-
exists(PutBundleExtraMethodAccess pba |
157-
node1.asExpr() = pba.getAnArgument() and node2.asExpr() = pba.getQualifier()
158-
)
159-
}
160-
161-
/**
162-
* Holds if broadcast doesn't specify receiving package name of the 3rd party app
163-
*/
164-
override predicate isSanitizer(DataFlow::Node node) {
165-
exists(MethodAccess setReceiverMa |
166-
setReceiverMa.getMethod().hasName(["setPackage", "setClass", "setClassName", "setComponent"]) and
167-
setReceiverMa.getQualifier().(VarAccess).getVariable().getAnAccess() = node.asExpr()
168-
)
169-
}
170-
}
171-
17218
from SensitiveBroadcastConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
17319
where cfg.hasFlowPath(source, sink)
17420
select sink.getNode(), source, sink, "Sending $@ to broadcast.", source.getNode(),
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/** Provides classes to reason about Android Sensitive Broadcast queries */
2+
3+
import java
4+
import semmle.code.java.dataflow.DataFlow3
5+
import semmle.code.java.dataflow.TaintTracking
6+
import semmle.code.java.frameworks.android.Intent
7+
import semmle.code.java.security.SensitiveActions
8+
9+
/**
10+
* Gets regular expression for matching names of Android variables that indicate the value being held contains sensitive information.
11+
*/
12+
private string getAndroidSensitiveInfoRegex() { result = "(?i).*(email|phone|ticket).*" }
13+
14+
/**
15+
* Method call to pass information to the `Intent` object.
16+
*/
17+
class PutIntentExtraMethodAccess extends MethodAccess {
18+
PutIntentExtraMethodAccess() {
19+
(
20+
getMethod().getName().matches("put%Extra") or
21+
getMethod().hasName("putExtras")
22+
) and
23+
getMethod().getDeclaringType() instanceof TypeIntent
24+
}
25+
}
26+
27+
/**
28+
* Method call to pass information to the intent extra bundle object.
29+
*/
30+
class PutBundleExtraMethodAccess extends MethodAccess {
31+
PutBundleExtraMethodAccess() {
32+
getMethod().getName().regexpMatch("put\\w+") and
33+
getMethod().getDeclaringType().getASupertype*().hasQualifiedName("android.os", "BaseBundle")
34+
}
35+
}
36+
37+
/** Finds variables that hold sensitive information judging by their names. */
38+
class SensitiveInfoExpr extends Expr {
39+
SensitiveInfoExpr() {
40+
exists(Variable v | this = v.getAnAccess() |
41+
v.getName().regexpMatch([getCommonSensitiveInfoRegex(), getAndroidSensitiveInfoRegex()])
42+
)
43+
}
44+
}
45+
46+
/**
47+
* A method access of the `Context.sendBroadcast` family.
48+
*/
49+
class SendBroadcastMethodAccess extends MethodAccess {
50+
SendBroadcastMethodAccess() {
51+
this.getMethod().getDeclaringType() instanceof TypeContext and
52+
this.getMethod().getName().matches("send%Broadcast%")
53+
}
54+
}
55+
56+
private class NullArgFlowConfig extends DataFlow2::Configuration {
57+
NullArgFlowConfig() { this = "Flow configuration with a null argument" }
58+
59+
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof NullLiteral }
60+
61+
override predicate isSink(DataFlow::Node sink) {
62+
exists(SendBroadcastMethodAccess ma | sink.asExpr() = ma.getAnArgument())
63+
}
64+
}
65+
66+
private class EmptyArrayArgFlowConfig extends DataFlow3::Configuration {
67+
EmptyArrayArgFlowConfig() { this = "Flow configuration with an empty array argument" }
68+
69+
override predicate isSource(DataFlow::Node src) {
70+
src.asExpr().(ArrayCreationExpr).getFirstDimensionSize() = 0
71+
}
72+
73+
override predicate isSink(DataFlow::Node sink) {
74+
exists(SendBroadcastMethodAccess ma | sink.asExpr() = ma.getAnArgument())
75+
}
76+
}
77+
78+
/**
79+
* Holds if a `sendBroadcast` call doesn't specify receiver permission.
80+
*/
81+
predicate isSensitiveBroadcastSink(DataFlow::Node sink) {
82+
exists(SendBroadcastMethodAccess ma |
83+
sink.asExpr() = ma.getAnArgument() and
84+
(
85+
ma.getMethod().hasName("sendBroadcast") and
86+
(
87+
ma.getNumArgument() = 1 // sendBroadcast(Intent intent)
88+
or
89+
// sendBroadcast(Intent intent, String receiverPermission)
90+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1))))
91+
)
92+
or
93+
ma.getMethod().hasName("sendBroadcastAsUser") and
94+
(
95+
ma.getNumArgument() = 2 or // sendBroadcastAsUser(Intent intent, UserHandle user)
96+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2)))) // sendBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission)
97+
)
98+
or
99+
ma.getMethod().hasName("sendBroadcastWithMultiplePermissions") and
100+
exists(EmptyArrayArgFlowConfig config |
101+
config.hasFlow(_, DataFlow::exprNode(ma.getArgument(1))) // sendBroadcastWithMultiplePermissions(Intent intent, String[] receiverPermissions)
102+
)
103+
or
104+
// Method calls of `sendOrderedBroadcast` whose second argument is always `receiverPermission`
105+
ma.getMethod().hasName("sendOrderedBroadcast") and
106+
(
107+
// sendOrderedBroadcast(Intent intent, String receiverPermission) or sendOrderedBroadcast(Intent intent, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
108+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1)))) and
109+
ma.getNumArgument() <= 7
110+
or
111+
// sendOrderedBroadcast(Intent intent, String receiverPermission, String receiverAppOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)
112+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(1)))) and
113+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2)))) and
114+
ma.getNumArgument() = 8
115+
)
116+
or
117+
// Method call of `sendOrderedBroadcastAsUser(Intent intent, UserHandle user, String receiverPermission, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras)`
118+
ma.getMethod().hasName("sendOrderedBroadcastAsUser") and
119+
exists(NullArgFlowConfig conf | conf.hasFlow(_, DataFlow::exprNode(ma.getArgument(2))))
120+
)
121+
)
122+
}
123+
124+
/**
125+
* Taint configuration tracking flow from variables containing sensitive information to broadcast intents.
126+
*/
127+
class SensitiveBroadcastConfig extends TaintTracking::Configuration {
128+
SensitiveBroadcastConfig() { this = "Sensitive Broadcast Configuration" }
129+
130+
override predicate isSource(DataFlow::Node source) {
131+
source.asExpr() instanceof SensitiveInfoExpr
132+
}
133+
134+
override predicate isSink(DataFlow::Node sink) { isSensitiveBroadcastSink(sink) }
135+
136+
/**
137+
* Holds if there is an additional flow step from `PutIntentExtraMethodAccess` or `PutBundleExtraMethodAccess` that taints the `Intent` or its extras `Bundle`.
138+
*/
139+
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
140+
exists(PutIntentExtraMethodAccess pia |
141+
node1.asExpr() = pia.getAnArgument() and node2.asExpr() = pia.getQualifier()
142+
)
143+
or
144+
exists(PutBundleExtraMethodAccess pba |
145+
node1.asExpr() = pba.getAnArgument() and node2.asExpr() = pba.getQualifier()
146+
)
147+
}
148+
149+
/**
150+
* Holds if broadcast doesn't specify receiving package name of the 3rd party app
151+
*/
152+
override predicate isSanitizer(DataFlow::Node node) {
153+
exists(MethodAccess setReceiverMa |
154+
setReceiverMa.getMethod().hasName(["setPackage", "setClass", "setClassName", "setComponent"]) and
155+
setReceiverMa.getQualifier().(VarAccess).getVariable().getAnAccess() = node.asExpr()
156+
)
157+
}
158+
}

0 commit comments

Comments
 (0)