Skip to content

Commit ed78d39

Browse files
committed
Move duplicate code to the shared library and update qldoc
1 parent b6a6ed5 commit ed78d39

File tree

5 files changed

+114
-129
lines changed

5 files changed

+114
-129
lines changed
Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Uncontrolled thread resource consumption from local input source
3-
* @description Use user input directly to control thread sleep time could lead to performance problems
4-
* or even resource exhaustion.
3+
* @description Using user input directly to control a thread's sleep time could lead to
4+
* performance problems or even resource exhaustion.
55
* @kind path-problem
66
* @id java/thread-resource-abuse
77
* @problem.severity recommendation
@@ -10,7 +10,7 @@
1010
*/
1111

1212
import java
13-
import ThreadPauseSink
13+
import ThreadResourceAbuse
1414
import semmle.code.java.dataflow.FlowSources
1515
import DataFlow::PathGraph
1616

@@ -40,18 +40,6 @@ class InitParameterInput extends LocalUserInput {
4040
InitParameterInput() { this.asExpr() instanceof GetInitParameterAccess }
4141
}
4242

43-
private class LessThanSanitizer extends DataFlow::BarrierGuard {
44-
LessThanSanitizer() { this instanceof ComparisonExpr }
45-
46-
override predicate checks(Expr e, boolean branch) {
47-
e = this.(ComparisonExpr).getLesserOperand() and
48-
branch = true
49-
or
50-
e = this.(ComparisonExpr).getGreaterOperand() and
51-
branch = false
52-
}
53-
}
54-
5543
/** Taint configuration of uncontrolled thread resource consumption from local user input. */
5644
class ThreadResourceAbuse extends TaintTracking::Configuration {
5745
ThreadResourceAbuse() { this = "ThreadResourceAbuse" }
@@ -60,34 +48,8 @@ class ThreadResourceAbuse extends TaintTracking::Configuration {
6048

6149
override predicate isSink(DataFlow::Node sink) { sink instanceof PauseThreadSink }
6250

63-
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
64-
exists(
65-
Method rm, ClassInstanceExpr ce, Argument arg, Parameter p, FieldAccess fa, int i // thread.start() invokes the run() method of thread implementation
66-
|
67-
rm.hasName("run") and
68-
ce.getConstructedType().getSourceDeclaration() = rm.getSourceDeclaration().getDeclaringType() and
69-
ce.getConstructedType().getASupertype*().hasQualifiedName("java.lang", "Runnable") and
70-
ce.getArgument(i) = arg and
71-
ce.getConstructor().getParameter(i) = p and
72-
fa.getEnclosingCallable() = rm and
73-
DataFlow::localExprFlow(p.getAnAccess(), fa.getField().getAnAssignedValue()) and
74-
node1.asExpr() = arg and
75-
node2.asExpr() = fa
76-
)
77-
or
78-
exists(Method um, VarAccess va, FieldAccess fa, Constructor ce, AssignExpr ar |
79-
um.getDeclaringType()
80-
.getASupertype*()
81-
.hasQualifiedName("org.apache.commons.fileupload", "ProgressListener") and
82-
um.hasName("update") and
83-
fa.getEnclosingCallable() = um and
84-
ce.getDeclaringType() = um.getDeclaringType() and
85-
va = ce.getAParameter().getAnAccess() and
86-
node1.asExpr() = va and
87-
node2.asExpr() = fa and
88-
ar.getSource() = va and
89-
ar.getDest() = fa.getField().getAnAccess()
90-
)
51+
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
52+
any(ThreadResourceAbuseAdditionalTaintStep r).propagatesTaint(pred, succ)
9153
}
9254

9355
override predicate isSanitizer(DataFlow::Node node) {
@@ -106,6 +68,5 @@ class ThreadResourceAbuse extends TaintTracking::Configuration {
10668

10769
from DataFlow::PathNode source, DataFlow::PathNode sink, ThreadResourceAbuse conf
10870
where conf.hasFlowPath(source, sink)
109-
select sink.getNode(), source, sink,
110-
"Vulnerability of uncontrolled resource consumption due to $@.", source.getNode(),
111-
"local user-provided value"
71+
select sink.getNode(), source, sink, "Possible uncontrolled resource consumption due to $@.",
72+
source.getNode(), "local user-provided value"

java/ql/src/experimental/Security/CWE/CWE-400/ThreadPauseSink.qll

Lines changed: 0 additions & 32 deletions
This file was deleted.

java/ql/src/experimental/Security/CWE/CWE-400/ThreadResourceAbuse.qhelp

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@
55

66

77
<overview>
8-
<p><code>Thread.sleep</code> method is used to pause the execution of current thread for specified
9-
time. When it is used to keep several relevant tasks in synchronization and the sleep time is
10-
user-controlled data, especially in the web application context, it can be abused to cause all
11-
of a server's threads to sleep, leading to denial of service.</p>
8+
<p>The <code>Thread.sleep</code> method is used to pause the execution of current thread for
9+
specified time. When the sleep time is user-controlled, especially in the web application context,
10+
it can be abused to cause all of a server's threads to sleep, leading to denial of service.</p>
1211
</overview>
1312

1413
<recommendation>
1514
<p>To guard against this attack, consider specifying an upper range of allowed sleep time or adopting
1615
the producer/consumer design pattern with <code>Object.wait</code> method to avoid performance
17-
problems or even resource exhaustion.</p>
16+
problems or even resource exhaustion. For more information, refer to the concurrency tutorial of Oracle
17+
listed below or <code>java/ql/src/Likely Bugs/Concurrency</code> queries of CodeQL.</p>
1818
</recommendation>
1919

2020
<example>
21-
<p>The following example shows the bad situation and the good situation respectively. In bad situation,
22-
a thread is spawned with the sleep time directly from user input. In good situation, an upper range
23-
check on maximum allowed sleep time is enforced.</p>
21+
<p>The following example shows a bad situation and a good situation respectively. In the bad situation,
22+
a thread is spawned with a sleep time coming directly from user input. In the good situation, an upper
23+
range check on the maximum sleep time allowed is enforced.</p>
2424
<sample src="ThreadResourceAbuse.java" />
2525
</example>
2626

@@ -40,5 +40,9 @@ The blog of a gypsy engineer:
4040
<a href="https://blog.gypsyengineer.com/en/security/cve-2019-17555-dos-via-retry-after-header-in-apache-olingo.html">
4141
CVE-2019-17555: DoS via Retry-After header in Apache Olingo</a>.
4242
</li>
43+
<li>
44+
Oracle:
45+
<a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html">The Java Concurrency Tutorials</a>
46+
</li>
4347
</references>
4448
</qhelp>

java/ql/src/experimental/Security/CWE/CWE-400/ThreadResourceAbuse.ql

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Uncontrolled thread resource consumption
3-
* @description Use user input directly to control thread sleep time could lead to performance problems
4-
* or even resource exhaustion.
3+
* @description Using user input directly to control a thread's sleep time could lead to
4+
* performance problems or even resource exhaustion.
55
* @kind path-problem
66
* @id java/thread-resource-abuse
77
* @problem.severity warning
@@ -10,22 +10,10 @@
1010
*/
1111

1212
import java
13-
import ThreadPauseSink
13+
import ThreadResourceAbuse
1414
import semmle.code.java.dataflow.FlowSources
1515
import DataFlow::PathGraph
1616

17-
private class LessThanSanitizer extends DataFlow::BarrierGuard {
18-
LessThanSanitizer() { this instanceof ComparisonExpr }
19-
20-
override predicate checks(Expr e, boolean branch) {
21-
e = this.(ComparisonExpr).getLesserOperand() and
22-
branch = true
23-
or
24-
e = this.(ComparisonExpr).getGreaterOperand() and
25-
branch = false
26-
}
27-
}
28-
2917
/** Taint configuration of uncontrolled thread resource consumption. */
3018
class ThreadResourceAbuse extends TaintTracking::Configuration {
3119
ThreadResourceAbuse() { this = "ThreadResourceAbuse" }
@@ -34,34 +22,8 @@ class ThreadResourceAbuse extends TaintTracking::Configuration {
3422

3523
override predicate isSink(DataFlow::Node sink) { sink instanceof PauseThreadSink }
3624

37-
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
38-
exists(
39-
Method rm, ClassInstanceExpr ce, Argument arg, Parameter p, FieldAccess fa, int i // thread.start() invokes the run() method of thread implementation
40-
|
41-
rm.hasName("run") and
42-
ce.getConstructedType().getSourceDeclaration() = rm.getSourceDeclaration().getDeclaringType() and
43-
ce.getConstructedType().getASupertype*().hasQualifiedName("java.lang", "Runnable") and
44-
ce.getArgument(i) = arg and
45-
ce.getConstructor().getParameter(i) = p and
46-
fa.getEnclosingCallable() = rm and
47-
DataFlow::localExprFlow(p.getAnAccess(), fa.getField().getAnAssignedValue()) and
48-
node1.asExpr() = arg and
49-
node2.asExpr() = fa
50-
)
51-
or
52-
exists(Method um, VarAccess va, FieldAccess fa, Constructor ce, AssignExpr ar |
53-
um.getDeclaringType()
54-
.getASupertype*()
55-
.hasQualifiedName("org.apache.commons.fileupload", "ProgressListener") and
56-
um.hasName("update") and
57-
fa.getEnclosingCallable() = um and
58-
ce.getDeclaringType() = um.getDeclaringType() and
59-
va = ce.getAParameter().getAnAccess() and
60-
node1.asExpr() = va and
61-
node2.asExpr() = fa and
62-
ar.getSource() = va and
63-
ar.getDest() = fa.getField().getAnAccess()
64-
)
25+
override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
26+
any(ThreadResourceAbuseAdditionalTaintStep r).propagatesTaint(pred, succ)
6527
}
6628

6729
override predicate isSanitizer(DataFlow::Node node) {
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/** Provides sink models and classes related to pausing thread operations. */
2+
3+
import java
4+
import semmle.code.java.dataflow.DataFlow
5+
import semmle.code.java.dataflow.ExternalFlow
6+
7+
/** `java.lang.Math` data model for value comparison in the new CSV format. */
8+
private class MathCompDataModel extends SummaryModelCsv {
9+
override predicate row(string row) {
10+
row =
11+
[
12+
"java.lang;Math;false;min;;;Argument[0..1];ReturnValue;value",
13+
"java.lang;Math;false;max;;;Argument[0..1];ReturnValue;value"
14+
]
15+
}
16+
}
17+
18+
/** Thread pause data model in the new CSV format. */
19+
private class PauseThreadDataModel extends SinkModelCsv {
20+
override predicate row(string row) {
21+
row =
22+
[
23+
"java.lang;Thread;true;sleep;;;Argument[0];thread-pause",
24+
"java.util.concurrent;TimeUnit;true;sleep;;;Argument[0];thread-pause"
25+
]
26+
}
27+
}
28+
29+
/** A sink representing methods pausing a thread. */
30+
class PauseThreadSink extends DataFlow::Node {
31+
PauseThreadSink() { sinkNode(this, "thread-pause") }
32+
}
33+
34+
/** A sanitizer for lessThan check. */
35+
class LessThanSanitizer extends DataFlow::BarrierGuard instanceof ComparisonExpr {
36+
override predicate checks(Expr e, boolean branch) {
37+
e = this.(ComparisonExpr).getLesserOperand() and
38+
branch = true
39+
or
40+
e = this.(ComparisonExpr).getGreaterOperand() and
41+
branch = false
42+
}
43+
}
44+
45+
/**
46+
* A unit class for adding additional taint steps that are specific to thread resource abuse.
47+
*/
48+
class ThreadResourceAbuseAdditionalTaintStep extends Unit {
49+
/**
50+
* Holds if the step from `pred` to `succ` should be considered a taint
51+
* step for thread resource abuse.
52+
*/
53+
abstract predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ);
54+
}
55+
56+
private class RunnableAdditionalTaintStep extends ThreadResourceAbuseAdditionalTaintStep {
57+
override predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ) {
58+
exists(
59+
Method rm, ClassInstanceExpr ce, Argument arg, Parameter p, FieldAccess fa, int i // thread.start() invokes the run() method of thread implementation
60+
|
61+
rm.hasName("run") and
62+
ce.getConstructedType().getSourceDeclaration() = rm.getSourceDeclaration().getDeclaringType() and
63+
ce.getConstructedType().getASupertype*().hasQualifiedName("java.lang", "Runnable") and
64+
ce.getArgument(i) = arg and
65+
ce.getConstructor().getParameter(i) = p and
66+
fa.getEnclosingCallable() = rm and
67+
DataFlow::localExprFlow(p.getAnAccess(), fa.getField().getAnAssignedValue()) and
68+
pred.asExpr() = arg and
69+
succ.asExpr() = fa
70+
)
71+
}
72+
}
73+
74+
private class ApacheFileUploadAdditionalTaintStep extends ThreadResourceAbuseAdditionalTaintStep {
75+
override predicate propagatesTaint(DataFlow::Node pred, DataFlow::Node succ) {
76+
exists(Method um, VarAccess va, FieldAccess fa, Constructor ce, AssignExpr ar |
77+
um.getDeclaringType()
78+
.getASupertype*()
79+
.hasQualifiedName("org.apache.commons.fileupload", "ProgressListener") and
80+
um.hasName("update") and
81+
fa.getEnclosingCallable() = um and
82+
ce.getDeclaringType() = um.getDeclaringType() and
83+
va = ce.getAParameter().getAnAccess() and
84+
pred.asExpr() = va and
85+
succ.asExpr() = fa and
86+
ar.getSource() = va and
87+
ar.getDest() = fa.getField().getAnAccess()
88+
)
89+
}
90+
}

0 commit comments

Comments
 (0)