Skip to content

Commit 2b9daed

Browse files
authored
Merge pull request github#12563 from egregius313/egregius313/refactor-java-libs-to-dataflow-modules
Java: Refactor Java query libraries to use dataflow modules
2 parents c1a7d7f + 800411c commit 2b9daed

File tree

60 files changed

+959
-520
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+959
-520
lines changed

java/ql/lib/semmle/code/java/frameworks/JsonIo.qll

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,12 @@ class JsonIoUseMapsSetter extends MethodAccess {
4242
}
4343
}
4444

45-
/** A data flow configuration tracing flow from JsonIo safe settings. */
46-
class SafeJsonIoConfig extends DataFlow2::Configuration {
45+
/**
46+
* DEPRECATED: Use `SafeJsonIoFlow` instead.
47+
*
48+
* A data flow configuration tracing flow from JsonIo safe settings.
49+
*/
50+
deprecated class SafeJsonIoConfig extends DataFlow2::Configuration {
4751
SafeJsonIoConfig() { this = "UnsafeDeserialization::SafeJsonIoConfig" }
4852

4953
override predicate isSource(DataFlow::Node src) {
@@ -65,3 +69,30 @@ class SafeJsonIoConfig extends DataFlow2::Configuration {
6569
)
6670
}
6771
}
72+
73+
/**
74+
* A data flow configuration tracing flow from JsonIo safe settings.
75+
*/
76+
module SafeJsonIoConfig implements DataFlow::ConfigSig {
77+
predicate isSource(DataFlow::Node src) {
78+
exists(MethodAccess ma |
79+
ma instanceof JsonIoUseMapsSetter and
80+
src.asExpr() = ma.getQualifier()
81+
)
82+
}
83+
84+
predicate isSink(DataFlow::Node sink) {
85+
exists(MethodAccess ma |
86+
ma.getMethod() instanceof JsonIoJsonToJavaMethod and
87+
sink.asExpr() = ma.getArgument(1)
88+
)
89+
or
90+
exists(ClassInstanceExpr cie |
91+
cie.getConstructor().getDeclaringType() instanceof JsonIoJsonReader and
92+
sink.asExpr() = cie.getArgument(1)
93+
)
94+
}
95+
}
96+
97+
/** Tracks flow from JsonIo safe settings. */
98+
module SafeJsonIoFlow = DataFlow::Global<SafeJsonIoConfig>;

java/ql/lib/semmle/code/java/frameworks/SnakeYaml.qll

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
import java
66
import semmle.code.java.dataflow.DataFlow
7-
import semmle.code.java.dataflow.DataFlow2
8-
import semmle.code.java.dataflow.DataFlow3
97

108
/**
119
* The class `org.yaml.snakeyaml.constructor.SafeConstructor`.
@@ -30,28 +28,28 @@ class Yaml extends RefType {
3028
Yaml() { this.getAnAncestor().hasQualifiedName("org.yaml.snakeyaml", "Yaml") }
3129
}
3230

33-
private class SafeYamlConstructionFlowConfig extends DataFlow3::Configuration {
34-
SafeYamlConstructionFlowConfig() { this = "SnakeYaml::SafeYamlConstructionFlowConfig" }
31+
private DataFlow::ExprNode yamlClassInstanceExprArgument(ClassInstanceExpr cie) {
32+
cie.getConstructedType() instanceof Yaml and
33+
result.getExpr() = cie.getArgument(0)
34+
}
3535

36-
override predicate isSource(DataFlow::Node src) {
37-
src.asExpr() instanceof SafeSnakeYamlConstruction
38-
}
36+
private module SafeYamlConstructionFlowConfig implements DataFlow::ConfigSig {
37+
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeSnakeYamlConstruction }
3938

40-
override predicate isSink(DataFlow::Node sink) { sink = this.yamlClassInstanceExprArgument(_) }
39+
predicate isSink(DataFlow::Node sink) { sink = yamlClassInstanceExprArgument(_) }
4140

42-
private DataFlow::ExprNode yamlClassInstanceExprArgument(ClassInstanceExpr cie) {
43-
cie.getConstructedType() instanceof Yaml and
44-
result.getExpr() = cie.getArgument(0)
41+
additional ClassInstanceExpr getSafeYaml() {
42+
SafeYamlConstructionFlow::flowTo(yamlClassInstanceExprArgument(result))
4543
}
46-
47-
ClassInstanceExpr getSafeYaml() { this.hasFlowTo(this.yamlClassInstanceExprArgument(result)) }
4844
}
4945

46+
private module SafeYamlConstructionFlow = DataFlow::Global<SafeYamlConstructionFlowConfig>;
47+
5048
/**
5149
* An instance of `Yaml` that does not allow arbitrary constructor to be called.
5250
*/
5351
private class SafeYaml extends ClassInstanceExpr {
54-
SafeYaml() { exists(SafeYamlConstructionFlowConfig conf | conf.getSafeYaml() = this) }
52+
SafeYaml() { SafeYamlConstructionFlowConfig::getSafeYaml() = this }
5553
}
5654

5755
/** A call to a parse method of `Yaml`. */
@@ -65,23 +63,25 @@ private class SnakeYamlParse extends MethodAccess {
6563
}
6664
}
6765

68-
private class SafeYamlFlowConfig extends DataFlow2::Configuration {
69-
SafeYamlFlowConfig() { this = "SnakeYaml::SafeYamlFlowConfig" }
66+
private module SafeYamlFlowConfig implements DataFlow::ConfigSig {
67+
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeYaml }
7068

71-
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof SafeYaml }
69+
predicate isSink(DataFlow::Node sink) { sink = yamlParseQualifier(_) }
7270

73-
override predicate isSink(DataFlow::Node sink) { sink = this.yamlParseQualifier(_) }
74-
75-
private DataFlow::ExprNode yamlParseQualifier(SnakeYamlParse syp) {
71+
additional DataFlow::ExprNode yamlParseQualifier(SnakeYamlParse syp) {
7672
result.getExpr() = syp.getQualifier()
7773
}
7874

79-
SnakeYamlParse getASafeSnakeYamlParse() { this.hasFlowTo(this.yamlParseQualifier(result)) }
75+
additional SnakeYamlParse getASafeSnakeYamlParse() {
76+
SafeYamlFlow::flowTo(yamlParseQualifier(result))
77+
}
8078
}
8179

80+
private module SafeYamlFlow = DataFlow::Global<SafeYamlFlowConfig>;
81+
8282
/**
8383
* A call to a parse method of `Yaml` that allows arbitrary constructor to be called.
8484
*/
8585
class UnsafeSnakeYamlParse extends SnakeYamlParse {
86-
UnsafeSnakeYamlParse() { not exists(SafeYamlFlowConfig sy | sy.getASafeSnakeYamlParse() = this) }
86+
UnsafeSnakeYamlParse() { not SafeYamlFlowConfig::getASafeSnakeYamlParse() = this }
8787
}

java/ql/lib/semmle/code/java/regex/RegexFlowConfigs.qll

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -136,24 +136,22 @@ private class GuavaRegexFlowStep extends RegexAdditionalFlowStep {
136136
}
137137
}
138138

139-
private class RegexFlowConf extends DataFlow2::Configuration {
140-
RegexFlowConf() { this = "RegexFlowConfig" }
139+
private module RegexFlowConfig implements DataFlow::ConfigSig {
140+
predicate isSource(DataFlow::Node node) { node.asExpr() instanceof ExploitableStringLiteral }
141141

142-
override predicate isSource(DataFlow::Node node) {
143-
node.asExpr() instanceof ExploitableStringLiteral
144-
}
145-
146-
override predicate isSink(DataFlow::Node node) { node instanceof RegexFlowSink }
142+
predicate isSink(DataFlow::Node node) { node instanceof RegexFlowSink }
147143

148-
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
144+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
149145
any(RegexAdditionalFlowStep s).step(node1, node2)
150146
}
151147

152-
override predicate isBarrier(DataFlow::Node node) {
148+
predicate isBarrier(DataFlow::Node node) {
153149
node.getEnclosingCallable().getDeclaringType() instanceof NonSecurityTestClass
154150
}
155151
}
156152

153+
private module RegexFlow = DataFlow::Global<RegexFlowConfig>;
154+
157155
/**
158156
* Holds if `regex` is used as a regex, with the mode `mode` (if known).
159157
* If regex mode is not known, `mode` will be `"None"`.
@@ -162,7 +160,7 @@ private class RegexFlowConf extends DataFlow2::Configuration {
162160
* and therefore may be relevant for ReDoS queries are considered.
163161
*/
164162
predicate usedAsRegex(StringLiteral regex, string mode, boolean match_full_string) {
165-
any(RegexFlowConf c).hasFlow(DataFlow2::exprNode(regex), _) and
163+
RegexFlow::flow(DataFlow::exprNode(regex), _) and
166164
mode = "None" and // TODO: proper mode detection
167165
(if matchesFullString(regex) then match_full_string = true else match_full_string = false)
168166
}
@@ -172,9 +170,9 @@ predicate usedAsRegex(StringLiteral regex, string mode, boolean match_full_strin
172170
* as though it was implicitly surrounded by ^ and $.
173171
*/
174172
private predicate matchesFullString(StringLiteral regex) {
175-
exists(RegexFlowConf c, RegexFlowSink sink |
173+
exists(RegexFlowSink sink |
176174
sink.matchesFullString() and
177-
c.hasFlow(DataFlow2::exprNode(regex), sink)
175+
RegexFlow::flow(DataFlow::exprNode(regex), sink)
178176
)
179177
}
180178

@@ -185,8 +183,8 @@ private predicate matchesFullString(StringLiteral regex) {
185183
* and therefore may be relevant for ReDoS queries are considered.
186184
*/
187185
predicate regexMatchedAgainst(StringLiteral regex, Expr str) {
188-
exists(RegexFlowConf c, RegexFlowSink sink |
186+
exists(RegexFlowSink sink |
189187
str = sink.getStringArgument() and
190-
c.hasFlow(DataFlow2::exprNode(regex), sink)
188+
RegexFlow::flow(DataFlow::exprNode(regex), sink)
191189
)
192190
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,10 @@ deprecated class SensitiveCommunicationConfig extends TaintTracking::Configurati
151151
}
152152
}
153153

154-
private module SensitiveCommunicationConfig implements DataFlow::ConfigSig {
154+
/**
155+
* Taint configuration tracking flow from variables containing sensitive information to broadcast Intents.
156+
*/
157+
module SensitiveCommunicationConfig implements DataFlow::ConfigSig {
155158
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveInfoExpr }
156159

157160
predicate isSink(DataFlow::Node sink) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ private import semmle.code.java.security.ArbitraryApkInstallation
99
* A dataflow configuration for flow from an external source of an APK to the
1010
* `setData[AndType][AndNormalize]` method of an intent.
1111
*/
12-
private module ApkInstallationConfig implements DataFlow::ConfigSig {
12+
module ApkInstallationConfig implements DataFlow::ConfigSig {
1313
predicate isSource(DataFlow::Node node) { node instanceof ExternalApkSource }
1414

1515
predicate isSink(DataFlow::Node node) {

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ class LocalDatabaseOpenMethodAccess extends Storable, Call {
2929
}
3030

3131
override Expr getAnInput() {
32-
exists(LocalDatabaseFlowConfig config, DataFlow::Node database |
32+
exists(DataFlow::Node database |
3333
localDatabaseInput(database, result) and
34-
config.hasFlow(DataFlow::exprNode(this), database)
34+
LocalDatabaseFlow::flow(DataFlow::exprNode(this), database)
3535
)
3636
}
3737

3838
override Expr getAStore() {
39-
exists(LocalDatabaseFlowConfig config, DataFlow::Node database |
39+
exists(DataFlow::Node database |
4040
localDatabaseStore(database, result) and
41-
config.hasFlow(DataFlow::exprNode(this), database)
41+
LocalDatabaseFlow::flow(DataFlow::exprNode(this), database)
4242
)
4343
}
4444
}
@@ -93,19 +93,17 @@ private predicate localDatabaseStore(DataFlow::Node database, MethodAccess store
9393
)
9494
}
9595

96-
private class LocalDatabaseFlowConfig extends DataFlow::Configuration {
97-
LocalDatabaseFlowConfig() { this = "LocalDatabaseFlowConfig" }
98-
99-
override predicate isSource(DataFlow::Node source) {
96+
private module LocalDatabaseFlowConfig implements DataFlow::ConfigSig {
97+
predicate isSource(DataFlow::Node source) {
10098
source.asExpr() instanceof LocalDatabaseOpenMethodAccess
10199
}
102100

103-
override predicate isSink(DataFlow::Node sink) {
101+
predicate isSink(DataFlow::Node sink) {
104102
localDatabaseInput(sink, _) or
105103
localDatabaseStore(sink, _)
106104
}
107105

108-
override predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
106+
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
109107
// Adds a step for tracking databases through field flow, that is, a database is opened and
110108
// assigned to a field, and then an input or store method is called on that field elsewhere.
111109
exists(Field f |
@@ -115,3 +113,5 @@ private class LocalDatabaseFlowConfig extends DataFlow::Configuration {
115113
)
116114
}
117115
}
116+
117+
private module LocalDatabaseFlow = DataFlow::Global<LocalDatabaseFlowConfig>;

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,16 @@ class LocalFileOpenCall extends Storable {
2424
}
2525

2626
override Expr getAnInput() {
27-
exists(FilesystemFlowConfig conf, DataFlow::Node n |
27+
exists(DataFlow::Node n |
2828
filesystemInput(n, result) and
29-
conf.hasFlow(DataFlow::exprNode(this), n)
29+
FilesystemFlow::flow(DataFlow::exprNode(this), n)
3030
)
3131
}
3232

3333
override Expr getAStore() {
34-
exists(FilesystemFlowConfig conf, DataFlow::Node n |
34+
exists(DataFlow::Node n |
3535
closesFile(n, result) and
36-
conf.hasFlow(DataFlow::exprNode(this), n)
36+
FilesystemFlow::flow(DataFlow::exprNode(this), n)
3737
)
3838
}
3939
}
@@ -79,17 +79,15 @@ private class CloseFileMethod extends Method {
7979
}
8080
}
8181

82-
private class FilesystemFlowConfig extends DataFlow::Configuration {
83-
FilesystemFlowConfig() { this = "FilesystemFlowConfig" }
82+
private module FilesystemFlowConfig implements DataFlow::ConfigSig {
83+
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof LocalFileOpenCall }
8484

85-
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof LocalFileOpenCall }
86-
87-
override predicate isSink(DataFlow::Node sink) {
85+
predicate isSink(DataFlow::Node sink) {
8886
filesystemInput(sink, _) or
8987
closesFile(sink, _)
9088
}
9189

92-
override predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
90+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
9391
// Add nested Writer constructors as extra data flow steps
9492
exists(ClassInstanceExpr cie |
9593
cie.getConstructedType().getAnAncestor().hasQualifiedName("java.io", "Writer") and
@@ -98,3 +96,5 @@ private class FilesystemFlowConfig extends DataFlow::Configuration {
9896
)
9997
}
10098
}
99+
100+
private module FilesystemFlow = DataFlow::Global<FilesystemFlowConfig>;

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

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ private class ClassCleartextStorageSink extends CleartextStorageSink {
1414
abstract class ClassStore extends Storable, ClassInstanceExpr {
1515
/** Gets an input, for example `input` in `instance.password = input`. */
1616
override Expr getAnInput() {
17-
exists(ClassStoreFlowConfig conf, DataFlow::Node instance |
18-
conf.hasFlow(DataFlow::exprNode(this), instance) and
17+
exists(DataFlow::Node instance |
18+
ClassStoreFlow::flow(DataFlow::exprNode(this), instance) and
1919
result = getInstanceInput(instance, this.getConstructor().getDeclaringType())
2020
)
2121
}
@@ -40,9 +40,9 @@ private class Serializable extends ClassStore {
4040

4141
/** Gets a store, for example `outputStream.writeObject(instance)`. */
4242
override Expr getAStore() {
43-
exists(ClassStoreFlowConfig conf, DataFlow::Node n |
43+
exists(DataFlow::Node n |
4444
serializableStore(n, result) and
45-
conf.hasFlow(DataFlow::exprNode(this), n)
45+
ClassStoreFlow::flow(DataFlow::exprNode(this), n)
4646
)
4747
}
4848
}
@@ -53,9 +53,9 @@ private class Marshallable extends ClassStore {
5353

5454
/** Gets a store, for example `marshaller.marshal(instance)`. */
5555
override Expr getAStore() {
56-
exists(ClassStoreFlowConfig conf, DataFlow::Node n |
56+
exists(DataFlow::Node n |
5757
marshallableStore(n, result) and
58-
conf.hasFlow(DataFlow::exprNode(this), n)
58+
ClassStoreFlow::flow(DataFlow::exprNode(this), n)
5959
)
6060
}
6161
}
@@ -73,20 +73,20 @@ private Expr getInstanceInput(DataFlow::Node instance, RefType t) {
7373
)
7474
}
7575

76-
private class ClassStoreFlowConfig extends DataFlow::Configuration {
77-
ClassStoreFlowConfig() { this = "ClassStoreFlowConfig" }
76+
private module ClassStoreFlowConfig implements DataFlow::ConfigSig {
77+
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ClassStore }
7878

79-
override predicate isSource(DataFlow::Node src) { src.asExpr() instanceof ClassStore }
80-
81-
override predicate isSink(DataFlow::Node sink) {
79+
predicate isSink(DataFlow::Node sink) {
8280
exists(getInstanceInput(sink, _)) or
8381
serializableStore(sink, _) or
8482
marshallableStore(sink, _)
8583
}
8684

87-
override int fieldFlowBranchLimit() { result = 1 }
85+
int fieldFlowBranchLimit() { result = 1 }
8886
}
8987

88+
private module ClassStoreFlow = DataFlow::Global<ClassStoreFlowConfig>;
89+
9090
private predicate serializableStore(DataFlow::Node instance, Expr store) {
9191
exists(MethodAccess m |
9292
store = m and

0 commit comments

Comments
 (0)