Skip to content

Commit 1b13597

Browse files
Implement checks for calls that may safely mask information
1 parent 5dd0add commit 1b13597

File tree

3 files changed

+94
-66
lines changed

3 files changed

+94
-66
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/** Provides classes and predicates for working with Android layouts and UI elements. */
2+
3+
import java
4+
import semmle.code.xml.AndroidManifest
5+
private import semmle.code.java.dataflow.DataFlow
6+
7+
/** An Android Layout XML file. */
8+
class AndroidLayoutXmlFile extends XmlFile {
9+
AndroidLayoutXmlFile() { this.getRelativePath().matches("%/res/layout/%.xml") }
10+
}
11+
12+
/** A component declared in an Android layout file. */
13+
class AndroidLayoutXmlElement extends XmlElement {
14+
AndroidXmlAttribute id;
15+
16+
AndroidLayoutXmlElement() {
17+
this.getFile() instanceof AndroidLayoutXmlFile and
18+
id = this.getAttribute("id")
19+
}
20+
21+
/** Gets the ID of this component. */
22+
string getId() { result = id.getValue() }
23+
24+
/** Gets the class of this component. */
25+
Class getClass() {
26+
this.getName() = "view" and
27+
this.getAttribute("class").getValue() = result.getQualifiedName()
28+
or
29+
this.getName() = result.getQualifiedName()
30+
or
31+
result.hasQualifiedName(["android.widget", "android.view"], this.getName())
32+
}
33+
}
34+
35+
/** An XML element that represents an editable text field. */
36+
class AndroidEditableXmlElement extends AndroidLayoutXmlElement {
37+
AndroidEditableXmlElement() {
38+
this.getClass().getASourceSupertype*().hasQualifiedName("android.widget", "EditText")
39+
}
40+
41+
/** Gets the input type of this field, if any. */
42+
string getInputType() { result = this.getAttribute("inputType").(AndroidXmlAttribute).getValue() }
43+
}
44+
45+
/** A `findViewById` or `requireViewById` method on `Activity` or `View`. */
46+
private class FindViewMethod extends Method {
47+
FindViewMethod() {
48+
this.hasQualifiedName("android.view", "View", ["findViewById", "requireViewById"])
49+
or
50+
exists(Method m |
51+
m.hasQualifiedName("android.app", "Activity", ["findViewById", "requireViewById"]) and
52+
this = m.getAnOverride*()
53+
)
54+
}
55+
}
56+
57+
/** Gets a use of the view that has the given id. (i.e. from a call to a method like `findViewById`) */
58+
MethodCall getAUseOfViewWithId(string id) {
59+
exists(string name, NestedClass r_id, Field id_field |
60+
id = "@+id/" + name and
61+
result.getMethod() instanceof FindViewMethod and
62+
r_id.getEnclosingType().hasName("R") and
63+
r_id.hasName("id") and
64+
id_field.getDeclaringType() = r_id and
65+
id_field.hasName(name)
66+
|
67+
DataFlow::localExprFlow(id_field.getAnAccess(), result.getArgument(0))
68+
)
69+
}

java/ql/lib/semmle/code/java/security/SensitiveKeyboardCacheQuery.qll

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,71 +3,7 @@
33
import java
44
import semmle.code.java.dataflow.DataFlow
55
import semmle.code.java.security.SensitiveActions
6-
import semmle.code.xml.AndroidManifest
7-
8-
/** An Android Layout XML file. */
9-
private class AndroidLayoutXmlFile extends XmlFile {
10-
AndroidLayoutXmlFile() { this.getRelativePath().matches("%/res/layout/%.xml") }
11-
}
12-
13-
/** A component declared in an Android layout file. */
14-
class AndroidLayoutXmlElement extends XmlElement {
15-
AndroidXmlAttribute id;
16-
17-
AndroidLayoutXmlElement() {
18-
this.getFile() instanceof AndroidLayoutXmlFile and
19-
id = this.getAttribute("id")
20-
}
21-
22-
/** Gets the ID of this component. */
23-
string getId() { result = id.getValue() }
24-
25-
/** Gets the class of this component. */
26-
Class getClass() {
27-
this.getName() = "view" and
28-
this.getAttribute("class").getValue() = result.getQualifiedName()
29-
or
30-
this.getName() = result.getQualifiedName()
31-
or
32-
result.hasQualifiedName(["android.widget", "android.view"], this.getName())
33-
}
34-
}
35-
36-
/** An XML element that represents an editable text field. */
37-
class AndroidEditableXmlElement extends AndroidLayoutXmlElement {
38-
AndroidEditableXmlElement() {
39-
this.getClass().getASourceSupertype*().hasQualifiedName("android.widget", "EditText")
40-
}
41-
42-
/** Gets the input type of this field, if any. */
43-
string getInputType() { result = this.getAttribute("inputType").(AndroidXmlAttribute).getValue() }
44-
}
45-
46-
/** A `findViewById` or `requireViewById` method on `Activity` or `View`. */
47-
private class FindViewMethod extends Method {
48-
FindViewMethod() {
49-
this.hasQualifiedName("android.view", "View", ["findViewById", "requireViewById"])
50-
or
51-
exists(Method m |
52-
m.hasQualifiedName("android.app", "Activity", ["findViewById", "requireViewById"]) and
53-
this = m.getAnOverride*()
54-
)
55-
}
56-
}
57-
58-
/** Gets a use of the view that has the given id. */
59-
private MethodCall getAUseOfViewWithId(string id) {
60-
exists(string name, NestedClass r_id, Field id_field |
61-
id = "@+id/" + name and
62-
result.getMethod() instanceof FindViewMethod and
63-
r_id.getEnclosingType().hasName("R") and
64-
r_id.hasName("id") and
65-
id_field.getDeclaringType() = r_id and
66-
id_field.hasName(name)
67-
|
68-
DataFlow::localExprFlow(id_field.getAnAccess(), result.getArgument(0))
69-
)
70-
}
6+
import semmle.code.java.frameworks.android.Layout
717

728
/** Gets the argument of a use of `setInputType` called on the view with the given id. */
739
private Argument setInputTypeForId(string id) {

java/ql/lib/semmle/code/java/security/SensitiveUiQuery.qll

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import java
44
private import semmle.code.java.dataflow.ExternalFlow
55
private import semmle.code.java.dataflow.TaintTracking
66
private import semmle.code.java.security.SensitiveActions
7+
private import semmle.code.java.frameworks.android.Layout
78

89
/** A configuration for tracking sensitive information to system notifications. */
910
private module NotificationTrackingConfig implements DataFlow::ConfigSig {
@@ -42,16 +43,38 @@ private class SetTextCall extends MethodCall {
4243
Expr getStringArgument() { result = this.getArgument(0) }
4344
}
4445

46+
/** A call to a method indicating that the contents of a UI element are safely masked. */
47+
private class MaskCall extends MethodCall {
48+
MaskCall() {
49+
this.getMethod().hasQualifiedName("android.widget", "TextView", "setInputType")
50+
or
51+
this.getMethod().hasQualifiedName("android.widget", "view", "setVisibility")
52+
}
53+
}
54+
4555
/** A configuration for tracking sensitive information to text fields. */
4656
private module TextFieldTrackingConfig implements DataFlow::ConfigSig {
4757
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SensitiveExpr }
4858

49-
predicate isSink(DataFlow::Node sink) { sink.asExpr() = any(SetTextCall s).getStringArgument() }
59+
predicate isSink(DataFlow::Node sink) {
60+
exists(SetTextCall call |
61+
sink.asExpr() = call.getStringArgument() and
62+
not isMasked(call)
63+
)
64+
}
5065

5166
predicate isBarrier(DataFlow::Node node) {
5267
node.getType() instanceof PrimitiveType or node.getType() instanceof BoxedType
5368
}
5469
}
5570

71+
/** Holds if the qualifier of `call` is also called with a method that may mask the information displayed. */
72+
private predicate isMasked(SetTextCall call) {
73+
exists(string id |
74+
DataFlow::localExprFlow(getAUseOfViewWithId(id), call.getQualifier()) and
75+
DataFlow::localExprFlow(getAUseOfViewWithId(id), any(MaskCall mcall).getQualifier())
76+
)
77+
}
78+
5679
/** Taint tracking flow for sensitive data flowing to text fields. */
5780
module TextFieldTracking = TaintTracking::Global<NotificationTrackingConfig>;

0 commit comments

Comments
 (0)