Skip to content

Commit e8a7139

Browse files
authored
Merge pull request github#12476 from aschackmull/java/refactor-dataflow-queries-2
Java: Refactor more dataflow queries to the new API
2 parents 604d5f0 + 7c0e89f commit e8a7139

File tree

5 files changed

+100
-58
lines changed

5 files changed

+100
-58
lines changed

java/ql/lib/semmle/code/java/security/regexp/PolynomialReDoSQuery.qll

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,12 @@ private class LengthRestrictedMethod extends Method {
3232
}
3333
}
3434

35-
/** A configuration for Polynomial ReDoS queries. */
36-
class PolynomialRedosConfig extends TaintTracking::Configuration {
35+
/**
36+
* DEPRECATED: Use `PolynomialRedosFlow` instead.
37+
*
38+
* A configuration for Polynomial ReDoS queries.
39+
*/
40+
deprecated class PolynomialRedosConfig extends TaintTracking::Configuration {
3741
PolynomialRedosConfig() { this = "PolynomialRedosConfig" }
3842

3943
override predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
@@ -47,11 +51,34 @@ class PolynomialRedosConfig extends TaintTracking::Configuration {
4751
}
4852
}
4953

50-
/** Holds if there is flow from `source` to `sink` that is matched against the regexp term `regexp` that is vulnerable to Polynomial ReDoS. */
51-
predicate hasPolynomialReDoSResult(
54+
/**
55+
* DEPRECATED: Use `PolynomialRedosFlow` instead.
56+
*
57+
* Holds if there is flow from `source` to `sink` that is matched against the regexp term `regexp` that is vulnerable to Polynomial ReDoS.
58+
*/
59+
deprecated predicate hasPolynomialReDoSResult(
5260
DataFlow::PathNode source, DataFlow::PathNode sink,
5361
SuperlinearBackTracking::PolynomialBackTrackingTerm regexp
5462
) {
5563
any(PolynomialRedosConfig config).hasFlowPath(source, sink) and
5664
regexp.getRootTerm() = sink.getNode().(PolynomialRedosSink).getRegExp()
5765
}
66+
67+
/** A configuration for Polynomial ReDoS queries. */
68+
private module PolynomialRedosConfig implements DataFlow::ConfigSig {
69+
predicate isSource(DataFlow::Node src) { src instanceof RemoteFlowSource }
70+
71+
predicate isSink(DataFlow::Node sink) {
72+
exists(SuperlinearBackTracking::PolynomialBackTrackingTerm regexp |
73+
regexp.getRootTerm() = sink.(PolynomialRedosSink).getRegExp()
74+
)
75+
}
76+
77+
predicate isBarrier(DataFlow::Node node) {
78+
node.getType() instanceof PrimitiveType or
79+
node.getType() instanceof BoxedType or
80+
node.asExpr().(MethodAccess).getMethod() instanceof LengthRestrictedMethod
81+
}
82+
}
83+
84+
module PolynomialRedosFlow = TaintTracking::Make<PolynomialRedosConfig>;

java/ql/src/Security/CWE/CWE-190/ArithmeticTainted.ql

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,35 +15,39 @@
1515
import java
1616
import semmle.code.java.dataflow.FlowSources
1717
import ArithmeticCommon
18-
import DataFlow::PathGraph
1918

20-
class RemoteUserInputOverflowConfig extends TaintTracking::Configuration {
21-
RemoteUserInputOverflowConfig() { this = "ArithmeticTainted.ql:RemoteUserInputOverflowConfig" }
19+
module RemoteUserInputOverflowConfig implements DataFlow::ConfigSig {
20+
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2221

23-
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
22+
predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
2423

25-
override predicate isSink(DataFlow::Node sink) { overflowSink(_, sink.asExpr()) }
24+
predicate isBarrier(DataFlow::Node n) { overflowBarrier(n) }
25+
}
26+
27+
module RemoteUserInputUnderflowConfig implements DataFlow::ConfigSig {
28+
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2629

27-
override predicate isSanitizer(DataFlow::Node n) { overflowBarrier(n) }
30+
predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
31+
32+
predicate isBarrier(DataFlow::Node n) { underflowBarrier(n) }
2833
}
2934

30-
class RemoteUserInputUnderflowConfig extends TaintTracking::Configuration {
31-
RemoteUserInputUnderflowConfig() { this = "ArithmeticTainted.ql:RemoteUserInputUnderflowConfig" }
35+
module RemoteUserInputOverflow = TaintTracking::Make<RemoteUserInputOverflowConfig>;
3236

33-
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
37+
module RemoteUserInputUnderflow = TaintTracking::Make<RemoteUserInputUnderflowConfig>;
3438

35-
override predicate isSink(DataFlow::Node sink) { underflowSink(_, sink.asExpr()) }
39+
module Flow =
40+
DataFlow::MergePathGraph<RemoteUserInputOverflow::PathNode, RemoteUserInputUnderflow::PathNode, RemoteUserInputOverflow::PathGraph, RemoteUserInputUnderflow::PathGraph>;
3641

37-
override predicate isSanitizer(DataFlow::Node n) { underflowBarrier(n) }
38-
}
42+
import Flow::PathGraph
3943

40-
from DataFlow::PathNode source, DataFlow::PathNode sink, ArithExpr exp, string effect
44+
from Flow::PathNode source, Flow::PathNode sink, ArithExpr exp, string effect
4145
where
42-
any(RemoteUserInputOverflowConfig c).hasFlowPath(source, sink) and
46+
RemoteUserInputOverflow::hasFlowPath(source.asPathNode1(), sink.asPathNode1()) and
4347
overflowSink(exp, sink.getNode().asExpr()) and
4448
effect = "overflow"
4549
or
46-
any(RemoteUserInputUnderflowConfig c).hasFlowPath(source, sink) and
50+
RemoteUserInputUnderflow::hasFlowPath(source.asPathNode2(), sink.asPathNode2()) and
4751
underflowSink(exp, sink.getNode().asExpr()) and
4852
effect = "underflow"
4953
select exp, source, sink,

java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414
import java
1515
import semmle.code.java.os.OSCheck
1616
import TempDirUtils
17-
import DataFlow::PathGraph
18-
import semmle.code.java.dataflow.TaintTracking2
17+
import semmle.code.java.dataflow.TaintTracking
1918

2019
abstract private class MethodFileSystemFileCreation extends Method {
2120
MethodFileSystemFileCreation() { this.getDeclaringType() instanceof TypeFile }
@@ -127,19 +126,17 @@ private class IsSpecificWindowsSanitizer extends WindowsOsSanitizer {
127126
* A taint tracking configuration tracking the access of the system temporary directory
128127
* flowing to the creation of files or directories.
129128
*/
130-
private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Configuration {
131-
TempDirSystemGetPropertyToCreateConfig() { this = "TempDirSystemGetPropertyToCreateConfig" }
132-
133-
override predicate isSource(DataFlow::Node source) {
129+
module TempDirSystemGetPropertyToCreateConfig implements DataFlow::ConfigSig {
130+
predicate isSource(DataFlow::Node source) {
134131
source.asExpr() instanceof ExprSystemGetPropertyTempDirTainted
135132
}
136133

137-
override predicate isSink(DataFlow::Node sink) {
134+
predicate isSink(DataFlow::Node sink) {
138135
sink instanceof FileCreationSink and
139-
not any(TempDirSystemGetPropertyDirectlyToMkdirConfig config).hasFlowTo(sink)
136+
not TempDirSystemGetPropertyDirectlyToMkdir::hasFlowTo(sink)
140137
}
141138

142-
override predicate isSanitizer(DataFlow::Node sanitizer) {
139+
predicate isBarrier(DataFlow::Node sanitizer) {
143140
exists(FilesSanitizingCreationMethodAccess sanitisingMethodAccess |
144141
sanitizer.asExpr() = sanitisingMethodAccess.getArgument(0)
145142
)
@@ -148,6 +145,9 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf
148145
}
149146
}
150147

148+
module TempDirSystemGetPropertyToCreate =
149+
TaintTracking::Make<TempDirSystemGetPropertyToCreateConfig>;
150+
151151
/**
152152
* Configuration that tracks calls to to `mkdir` or `mkdirs` that are are directly on the temp directory system property.
153153
* Examples:
@@ -158,30 +158,29 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf
158158
* As such, this code pattern is filtered out as an explicit vulnerability in
159159
* `TempDirSystemGetPropertyToCreateConfig::isSink`.
160160
*/
161-
private class TempDirSystemGetPropertyDirectlyToMkdirConfig extends TaintTracking2::Configuration {
162-
TempDirSystemGetPropertyDirectlyToMkdirConfig() {
163-
this = "TempDirSystemGetPropertyDirectlyToMkdirConfig"
164-
}
165-
166-
override predicate isSource(DataFlow::Node node) {
161+
module TempDirSystemGetPropertyDirectlyToMkdirConfig implements DataFlow::ConfigSig {
162+
predicate isSource(DataFlow::Node node) {
167163
exists(ExprSystemGetPropertyTempDirTainted propertyGetExpr, DataFlow::Node callSite |
168164
DataFlow::localFlow(DataFlow::exprNode(propertyGetExpr), callSite)
169165
|
170166
isFileConstructorArgument(callSite.asExpr(), node.asExpr(), 1)
171167
)
172168
}
173169

174-
override predicate isSink(DataFlow::Node node) {
170+
predicate isSink(DataFlow::Node node) {
175171
exists(MethodAccess ma | ma.getMethod() instanceof MethodFileDirectoryCreation |
176172
ma.getQualifier() = node.asExpr()
177173
)
178174
}
179175

180-
override predicate isSanitizer(DataFlow::Node sanitizer) {
176+
predicate isBarrier(DataFlow::Node sanitizer) {
181177
isFileConstructorArgument(sanitizer.asExpr(), _, _)
182178
}
183179
}
184180

181+
module TempDirSystemGetPropertyDirectlyToMkdir =
182+
TaintTracking::Make<TempDirSystemGetPropertyDirectlyToMkdirConfig>;
183+
185184
//
186185
// Begin configuration for tracking single-method calls that are vulnerable.
187186
//
@@ -193,6 +192,8 @@ abstract class MethodAccessInsecureFileCreation extends MethodAccess {
193192
* Gets the type of entity created (e.g. `file`, `directory`, ...).
194193
*/
195194
abstract string getFileSystemEntityType();
195+
196+
DataFlow::Node getNode() { result.asExpr() = this }
196197
}
197198

198199
/**
@@ -235,39 +236,47 @@ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureF
235236
}
236237

237238
/**
238-
* A hack: we include use of inherently insecure methods, which don't have any associated
239+
* We include use of inherently insecure methods, which don't have any associated
239240
* flow path, in with results describing a path from reading `java.io.tmpdir` or similar to use
240241
* in a file creation op.
241242
*
242-
* We achieve this by making inherently-insecure method invocations both a source and a sink in
243-
* this configuration, resulting in a zero-length path which is type-compatible with the actual
244-
* path-flow results.
243+
* We achieve this by making inherently-insecure method invocations into an edge-less graph,
244+
* resulting in a zero-length paths.
245245
*/
246-
class InsecureMethodPseudoConfiguration extends DataFlow::Configuration {
247-
InsecureMethodPseudoConfiguration() { this = "InsecureMethodPseudoConfiguration" }
246+
module InsecureMethodPathGraph implements DataFlow::PathGraphSig<MethodAccessInsecureFileCreation> {
247+
predicate edges(MethodAccessInsecureFileCreation n1, MethodAccessInsecureFileCreation n2) {
248+
none()
249+
}
248250

249-
override predicate isSource(DataFlow::Node node) {
250-
node.asExpr() instanceof MethodAccessInsecureFileCreation
251+
predicate nodes(MethodAccessInsecureFileCreation n, string key, string val) {
252+
key = "semmle.label" and val = n.toString()
251253
}
252254

253-
override predicate isSink(DataFlow::Node node) {
254-
node.asExpr() instanceof MethodAccessInsecureFileCreation
255+
predicate subpaths(
256+
MethodAccessInsecureFileCreation n1, MethodAccessInsecureFileCreation n2,
257+
MethodAccessInsecureFileCreation n3, MethodAccessInsecureFileCreation n4
258+
) {
259+
none()
255260
}
256261
}
257262

258-
from DataFlow::PathNode source, DataFlow::PathNode sink, string message
263+
module Flow =
264+
DataFlow::MergePathGraph<TempDirSystemGetPropertyToCreate::PathNode, MethodAccessInsecureFileCreation, TempDirSystemGetPropertyToCreate::PathGraph, InsecureMethodPathGraph>;
265+
266+
import Flow::PathGraph
267+
268+
from Flow::PathNode source, Flow::PathNode sink, string message
259269
where
260270
(
261-
any(TempDirSystemGetPropertyToCreateConfig conf).hasFlowPath(source, sink) and
271+
TempDirSystemGetPropertyToCreate::hasFlowPath(source.asPathNode1(), sink.asPathNode1()) and
262272
message =
263273
"Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users."
264274
or
265-
any(InsecureMethodPseudoConfiguration conf).hasFlowPath(source, sink) and
275+
source = sink and
266276
// Note this message has no "$@" placeholder, so the "system temp directory" template parameter below is not used.
267277
message =
268278
"Local information disclosure vulnerability due to use of " +
269-
source.getNode().asExpr().(MethodAccessInsecureFileCreation).getFileSystemEntityType() +
270-
" readable by other local users."
279+
source.asPathNode2().getFileSystemEntityType() + " readable by other local users."
271280
) and
272281
not isPermissionsProtectedTempDirUse(sink.getNode())
273282
select source.getNode(), source, sink, message, source.getNode(), "system temp directory"

java/ql/src/Security/CWE/CWE-730/PolynomialReDoS.ql

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@
1515

1616
import java
1717
import semmle.code.java.security.regexp.PolynomialReDoSQuery
18-
import DataFlow::PathGraph
18+
import PolynomialRedosFlow::PathGraph
1919

2020
from
21-
DataFlow::PathNode source, DataFlow::PathNode sink,
21+
PolynomialRedosFlow::PathNode source, PolynomialRedosFlow::PathNode sink,
2222
SuperlinearBackTracking::PolynomialBackTrackingTerm regexp
23-
where hasPolynomialReDoSResult(source, sink, regexp)
23+
where
24+
PolynomialRedosFlow::hasFlowPath(source, sink) and
25+
regexp.getRootTerm() = sink.getNode().(PolynomialRedosSink).getRegExp()
2426
select sink, source, sink,
2527
"This $@ that depends on a $@ may run slow on strings " + regexp.getPrefixMessage() +
2628
"with many repetitions of '" + regexp.getPumpString() + "'.", regexp, "regular expression",

java/ql/test/query-tests/security/CWE-730/PolynomialReDoS.ql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ class HasPolyRedos extends InlineExpectationsTest {
88

99
override predicate hasActualResult(Location location, string element, string tag, string value) {
1010
tag = "hasPolyRedos" and
11-
exists(DataFlow::PathNode sink |
12-
hasPolynomialReDoSResult(_, sink, _) and
13-
location = sink.getNode().getLocation() and
14-
element = sink.getNode().toString() and
11+
exists(DataFlow::Node sink |
12+
PolynomialRedosFlow::hasFlowTo(sink) and
13+
location = sink.getLocation() and
14+
element = sink.toString() and
1515
value = ""
1616
)
1717
}

0 commit comments

Comments
 (0)