Skip to content

Commit 52e4076

Browse files
authored
Merge pull request github#12427 from aschackmull/java/refactor-dataflow-queries-1
Java: Refactor some dataflow queries to the new API
2 parents 8356991 + 64dd8b9 commit 52e4076

16 files changed

+175
-136
lines changed

Diff for: java/ql/lib/semmle/code/java/security/RequestForgeryConfig.qll

+26-1
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@ import semmle.code.java.dataflow.FlowSources
88
import semmle.code.java.security.RequestForgery
99

1010
/**
11+
* DEPRECATED: Use `RequestForgeryConfiguration` module instead.
12+
*
1113
* A taint-tracking configuration characterising request-forgery risks.
1214
*/
13-
class RequestForgeryConfiguration extends TaintTracking::Configuration {
15+
deprecated class RequestForgeryConfiguration extends TaintTracking::Configuration {
1416
RequestForgeryConfiguration() { this = "Server-Side Request Forgery" }
1517

1618
override predicate isSource(DataFlow::Node source) {
@@ -29,3 +31,26 @@ class RequestForgeryConfiguration extends TaintTracking::Configuration {
2931

3032
override predicate isSanitizer(DataFlow::Node node) { node instanceof RequestForgerySanitizer }
3133
}
34+
35+
/**
36+
* A taint-tracking configuration characterising request-forgery risks.
37+
*/
38+
private module RequestForgeryConfiguration implements DataFlow::ConfigSig {
39+
predicate isSource(DataFlow::Node source) {
40+
source instanceof RemoteFlowSource and
41+
// Exclude results of remote HTTP requests: fetching something else based on that result
42+
// is no worse than following a redirect returned by the remote server, and typically
43+
// we're requesting a resource via https which we trust to only send us to safe URLs.
44+
not source.asExpr().(MethodAccess).getCallee() instanceof UrlConnectionGetInputStreamMethod
45+
}
46+
47+
predicate isSink(DataFlow::Node sink) { sink instanceof RequestForgerySink }
48+
49+
predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) {
50+
any(RequestForgeryAdditionalTaintStep r).propagatesTaint(pred, succ)
51+
}
52+
53+
predicate isBarrier(DataFlow::Node node) { node instanceof RequestForgerySanitizer }
54+
}
55+
56+
module RequestForgeryFlow = TaintTracking::Make<RequestForgeryConfiguration>;

Diff for: java/ql/lib/semmle/code/java/security/SensitiveLoggingQuery.qll

+25-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,12 @@ private class TypeType extends RefType {
2525
}
2626
}
2727

28-
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
29-
class SensitiveLoggerConfiguration extends TaintTracking::Configuration {
28+
/**
29+
* DEPRECATED: Use `SensitiveLoggerConfiguration` module instead.
30+
*
31+
* A data-flow configuration for identifying potentially-sensitive data flowing to a log output.
32+
*/
33+
deprecated class SensitiveLoggerConfiguration extends TaintTracking::Configuration {
3034
SensitiveLoggerConfiguration() { this = "SensitiveLoggerConfiguration" }
3135

3236
override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
@@ -43,3 +47,22 @@ class SensitiveLoggerConfiguration extends TaintTracking::Configuration {
4347

4448
override predicate isSanitizerIn(Node node) { this.isSource(node) }
4549
}
50+
51+
/** A data-flow configuration for identifying potentially-sensitive data flowing to a log output. */
52+
private module SensitiveLoggerConfiguration implements DataFlow::ConfigSig {
53+
predicate isSource(DataFlow::Node source) { source.asExpr() instanceof CredentialExpr }
54+
55+
predicate isSink(DataFlow::Node sink) { sinkNode(sink, "logging") }
56+
57+
predicate isBarrier(DataFlow::Node sanitizer) {
58+
sanitizer.asExpr() instanceof LiveLiteral or
59+
sanitizer.getType() instanceof PrimitiveType or
60+
sanitizer.getType() instanceof BoxedType or
61+
sanitizer.getType() instanceof NumberType or
62+
sanitizer.getType() instanceof TypeType
63+
}
64+
65+
predicate isBarrierIn(Node node) { isSource(node) }
66+
}
67+
68+
module SensitiveLoggerFlow = TaintTracking::Make<SensitiveLoggerConfiguration>;

Diff for: java/ql/lib/semmle/code/java/security/XSS.qll

+9-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import semmle.code.java.frameworks.spring.SpringController
77
import semmle.code.java.frameworks.spring.SpringHttp
88
import semmle.code.java.frameworks.javaee.jsf.JSFRenderer
99
import semmle.code.java.dataflow.DataFlow
10-
import semmle.code.java.dataflow.TaintTracking2
10+
import semmle.code.java.dataflow.TaintTracking
1111
private import semmle.code.java.dataflow.ExternalFlow
1212

1313
/** A sink that represent a method that outputs data without applying contextual output encoding. */
@@ -41,9 +41,9 @@ private class DefaultXssSink extends XssSink {
4141
DefaultXssSink() {
4242
sinkNode(this, "xss")
4343
or
44-
exists(XssVulnerableWriterSourceToWritingMethodFlowConfig writer, MethodAccess ma |
44+
exists(MethodAccess ma |
4545
ma.getMethod() instanceof WritingMethod and
46-
writer.hasFlowToExpr(ma.getQualifier()) and
46+
XssVulnerableWriterSourceToWritingMethodFlow::hasFlowToExpr(ma.getQualifier()) and
4747
this.asExpr() = ma.getArgument(_)
4848
)
4949
}
@@ -60,23 +60,19 @@ private class DefaultXssSanitizer extends XssSanitizer {
6060
}
6161

6262
/** A configuration that tracks data from a servlet writer to an output method. */
63-
private class XssVulnerableWriterSourceToWritingMethodFlowConfig extends TaintTracking2::Configuration
64-
{
65-
XssVulnerableWriterSourceToWritingMethodFlowConfig() {
66-
this = "XSS::XssVulnerableWriterSourceToWritingMethodFlowConfig"
67-
}
63+
private module XssVulnerableWriterSourceToWritingMethodFlowConfig implements DataFlow::ConfigSig {
64+
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
6865

69-
override predicate isSource(DataFlow::Node src) {
70-
src.asExpr() instanceof XssVulnerableWriterSource
71-
}
72-
73-
override predicate isSink(DataFlow::Node sink) {
66+
predicate isSink(DataFlow::Node sink) {
7467
exists(MethodAccess ma |
7568
sink.asExpr() = ma.getQualifier() and ma.getMethod() instanceof WritingMethod
7669
)
7770
}
7871
}
7972

73+
private module XssVulnerableWriterSourceToWritingMethodFlow =
74+
TaintTracking::Make<XssVulnerableWriterSourceToWritingMethodFlowConfig>;
75+
8076
/** A method that can be used to output data to an output stream or writer. */
8177
private class WritingMethod extends Method {
8278
WritingMethod() {

Diff for: java/ql/src/Security/CWE/CWE-022/TaintedPath.ql

+12-11
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,33 @@ import semmle.code.java.dataflow.FlowSources
1818
private import semmle.code.java.dataflow.ExternalFlow
1919
import semmle.code.java.security.PathCreation
2020
import semmle.code.java.security.PathSanitizer
21-
import DataFlow::PathGraph
2221
import TaintedPathCommon
2322

24-
class TaintedPathConfig extends TaintTracking::Configuration {
25-
TaintedPathConfig() { this = "TaintedPathConfig" }
23+
module TaintedPathConfig implements DataFlow::ConfigSig {
24+
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2625

27-
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
28-
29-
override predicate isSink(DataFlow::Node sink) {
26+
predicate isSink(DataFlow::Node sink) {
3027
sink.asExpr() = any(PathCreation p).getAnInput()
3128
or
3229
sinkNode(sink, ["create-file", "read-file"])
3330
}
3431

35-
override predicate isSanitizer(DataFlow::Node sanitizer) {
32+
predicate isBarrier(DataFlow::Node sanitizer) {
3633
sanitizer.getType() instanceof BoxedType or
3734
sanitizer.getType() instanceof PrimitiveType or
3835
sanitizer.getType() instanceof NumberType or
3936
sanitizer instanceof PathInjectionSanitizer
4037
}
4138

42-
override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
39+
predicate isAdditionalFlowStep(DataFlow::Node n1, DataFlow::Node n2) {
4340
any(TaintedPathAdditionalTaintStep s).step(n1, n2)
4441
}
4542
}
4643

44+
module TaintedPath = TaintTracking::Make<TaintedPathConfig>;
45+
46+
import TaintedPath::PathGraph
47+
4748
/**
4849
* Gets the data-flow node at which to report a path ending at `sink`.
4950
*
@@ -52,13 +53,13 @@ class TaintedPathConfig extends TaintTracking::Configuration {
5253
* continue to report there; otherwise we report directly at `sink`.
5354
*/
5455
DataFlow::Node getReportingNode(DataFlow::Node sink) {
55-
any(TaintedPathConfig c).hasFlowTo(sink) and
56+
TaintedPath::hasFlowTo(sink) and
5657
if exists(PathCreation pc | pc.getAnInput() = sink.asExpr())
5758
then result.asExpr() = any(PathCreation pc | pc.getAnInput() = sink.asExpr())
5859
else result = sink
5960
}
6061

61-
from DataFlow::PathNode source, DataFlow::PathNode sink, TaintedPathConfig conf
62-
where conf.hasFlowPath(source, sink)
62+
from TaintedPath::PathNode source, TaintedPath::PathNode sink
63+
where TaintedPath::hasFlowPath(source, sink)
6364
select getReportingNode(sink.getNode()), source, sink, "This path depends on a $@.",
6465
source.getNode(), "user-provided value"

Diff for: java/ql/src/Security/CWE/CWE-079/XSS.ql

+12-11
Original file line numberDiff line numberDiff line change
@@ -14,25 +14,26 @@
1414
import java
1515
import semmle.code.java.dataflow.FlowSources
1616
import semmle.code.java.security.XSS
17-
import DataFlow::PathGraph
1817

19-
class XssConfig extends TaintTracking::Configuration {
20-
XssConfig() { this = "XSSConfig" }
18+
module XssConfig implements DataFlow::ConfigSig {
19+
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
2120

22-
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
21+
predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
2322

24-
override predicate isSink(DataFlow::Node sink) { sink instanceof XssSink }
23+
predicate isBarrier(DataFlow::Node node) { node instanceof XssSanitizer }
2524

26-
override predicate isSanitizer(DataFlow::Node node) { node instanceof XssSanitizer }
25+
predicate isBarrierOut(DataFlow::Node node) { node instanceof XssSinkBarrier }
2726

28-
override predicate isSanitizerOut(DataFlow::Node node) { node instanceof XssSinkBarrier }
29-
30-
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
27+
predicate isAdditionalFlowStep(DataFlow::Node node1, DataFlow::Node node2) {
3128
any(XssAdditionalTaintStep s).step(node1, node2)
3229
}
3330
}
3431

35-
from DataFlow::PathNode source, DataFlow::PathNode sink, XssConfig conf
36-
where conf.hasFlowPath(source, sink)
32+
module XssFlow = TaintTracking::Make<XssConfig>;
33+
34+
import XssFlow::PathGraph
35+
36+
from XssFlow::PathNode source, XssFlow::PathNode sink
37+
where XssFlow::hasFlowPath(source, sink)
3738
select sink.getNode(), source, sink, "Cross-site scripting vulnerability due to a $@.",
3839
source.getNode(), "user-provided value"

Diff for: java/ql/src/Security/CWE/CWE-113/ResponseSplitting.ql

+10-9
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,16 @@
1414
import java
1515
import semmle.code.java.dataflow.FlowSources
1616
import semmle.code.java.security.ResponseSplitting
17-
import DataFlow::PathGraph
1817

19-
class ResponseSplittingConfig extends TaintTracking::Configuration {
20-
ResponseSplittingConfig() { this = "ResponseSplittingConfig" }
21-
22-
override predicate isSource(DataFlow::Node source) {
18+
module ResponseSplittingConfig implements DataFlow::ConfigSig {
19+
predicate isSource(DataFlow::Node source) {
2320
source instanceof RemoteFlowSource and
2421
not source instanceof SafeHeaderSplittingSource
2522
}
2623

27-
override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
24+
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
2825

29-
override predicate isSanitizer(DataFlow::Node node) {
26+
predicate isBarrier(DataFlow::Node node) {
3027
node.getType() instanceof PrimitiveType
3128
or
3229
node.getType() instanceof BoxedType
@@ -45,8 +42,12 @@ class ResponseSplittingConfig extends TaintTracking::Configuration {
4542
}
4643
}
4744

48-
from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingConfig conf
49-
where conf.hasFlowPath(source, sink)
45+
module ResponseSplitting = TaintTracking::Make<ResponseSplittingConfig>;
46+
47+
import ResponseSplitting::PathGraph
48+
49+
from ResponseSplitting::PathNode source, ResponseSplitting::PathNode sink
50+
where ResponseSplitting::hasFlowPath(source, sink)
5051
select sink.getNode(), source, sink,
5152
"This header depends on a $@, which may cause a response-splitting vulnerability.",
5253
source.getNode(), "user-provided value"

Diff for: java/ql/src/Security/CWE/CWE-113/ResponseSplittingLocal.ql

+10-9
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,24 @@
1414
import java
1515
import semmle.code.java.dataflow.FlowSources
1616
import semmle.code.java.security.ResponseSplitting
17-
import DataFlow::PathGraph
1817

19-
class ResponseSplittingLocalConfig extends TaintTracking::Configuration {
20-
ResponseSplittingLocalConfig() { this = "ResponseSplittingLocalConfig" }
18+
module ResponseSplittingLocalConfig implements DataFlow::ConfigSig {
19+
predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
2120

22-
override predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
21+
predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
2322

24-
override predicate isSink(DataFlow::Node sink) { sink instanceof HeaderSplittingSink }
25-
26-
override predicate isSanitizer(DataFlow::Node node) {
23+
predicate isBarrier(DataFlow::Node node) {
2724
node.getType() instanceof PrimitiveType or
2825
node.getType() instanceof BoxedType
2926
}
3027
}
3128

32-
from DataFlow::PathNode source, DataFlow::PathNode sink, ResponseSplittingLocalConfig conf
33-
where conf.hasFlowPath(source, sink)
29+
module ResponseSplitting = TaintTracking::Make<ResponseSplittingLocalConfig>;
30+
31+
import ResponseSplitting::PathGraph
32+
33+
from ResponseSplitting::PathNode source, ResponseSplitting::PathNode sink
34+
where ResponseSplitting::hasFlowPath(source, sink)
3435
select sink.getNode(), source, sink,
3536
"This header depends on a $@, which may cause a response-splitting vulnerability.",
3637
source.getNode(), "user-provided value"

Diff for: java/ql/src/Security/CWE/CWE-209/StackTraceExposure.ql

+17-23
Original file line numberDiff line numberDiff line change
@@ -31,33 +31,27 @@ class PrintStackTraceMethod extends Method {
3131
}
3232
}
3333

34-
class ServletWriterSourceToPrintStackTraceMethodFlowConfig extends TaintTracking::Configuration {
35-
ServletWriterSourceToPrintStackTraceMethodFlowConfig() {
36-
this = "StackTraceExposure::ServletWriterSourceToPrintStackTraceMethodFlowConfig"
37-
}
38-
39-
override predicate isSource(DataFlow::Node src) {
40-
src.asExpr() instanceof XssVulnerableWriterSource
41-
}
34+
module ServletWriterSourceToPrintStackTraceMethodFlowConfig implements DataFlow::ConfigSig {
35+
predicate isSource(DataFlow::Node src) { src.asExpr() instanceof XssVulnerableWriterSource }
4236

43-
override predicate isSink(DataFlow::Node sink) {
37+
predicate isSink(DataFlow::Node sink) {
4438
exists(MethodAccess ma |
4539
sink.asExpr() = ma.getAnArgument() and ma.getMethod() instanceof PrintStackTraceMethod
4640
)
4741
}
4842
}
4943

44+
module ServletWriterSourceToPrintStackTraceMethodFlow =
45+
TaintTracking::Make<ServletWriterSourceToPrintStackTraceMethodFlowConfig>;
46+
5047
/**
5148
* A call that uses `Throwable.printStackTrace()` on a stream that is connected
5249
* to external output.
5350
*/
5451
predicate printsStackToWriter(MethodAccess call) {
55-
exists(
56-
ServletWriterSourceToPrintStackTraceMethodFlowConfig writerSource,
57-
PrintStackTraceMethod printStackTrace
58-
|
52+
exists(PrintStackTraceMethod printStackTrace |
5953
call.getMethod() = printStackTrace and
60-
writerSource.hasFlowToExpr(call.getAnArgument())
54+
ServletWriterSourceToPrintStackTraceMethodFlow::hasFlowToExpr(call.getAnArgument())
6155
)
6256
}
6357

@@ -86,16 +80,15 @@ predicate stackTraceExpr(Expr exception, MethodAccess stackTraceString) {
8680
)
8781
}
8882

89-
class StackTraceStringToHttpResponseSinkFlowConfig extends TaintTracking::Configuration {
90-
StackTraceStringToHttpResponseSinkFlowConfig() {
91-
this = "StackTraceExposure::StackTraceStringToHttpResponseSinkFlowConfig"
92-
}
93-
94-
override predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) }
83+
module StackTraceStringToHttpResponseSinkFlowConfig implements DataFlow::ConfigSig {
84+
predicate isSource(DataFlow::Node src) { stackTraceExpr(_, src.asExpr()) }
9585

96-
override predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
86+
predicate isSink(DataFlow::Node sink) { sink instanceof InformationLeakSink }
9787
}
9888

89+
module StackTraceStringToHttpResponseSinkFlow =
90+
TaintTracking::Make<StackTraceStringToHttpResponseSinkFlowConfig>;
91+
9992
/**
10093
* A write of stack trace data to an external stream.
10194
*/
@@ -109,9 +102,10 @@ predicate printsStackExternally(MethodAccess call, Expr stackTrace) {
109102
* A stringified stack trace flows to an external sink.
110103
*/
111104
predicate stringifiedStackFlowsExternally(DataFlow::Node externalExpr, Expr stackTrace) {
112-
exists(MethodAccess stackTraceString, StackTraceStringToHttpResponseSinkFlowConfig conf |
105+
exists(MethodAccess stackTraceString |
113106
stackTraceExpr(stackTrace, stackTraceString) and
114-
conf.hasFlow(DataFlow::exprNode(stackTraceString), externalExpr)
107+
StackTraceStringToHttpResponseSinkFlow::hasFlow(DataFlow::exprNode(stackTraceString),
108+
externalExpr)
115109
)
116110
}
117111

0 commit comments

Comments
 (0)