Skip to content

Commit b6a6ed5

Browse files
committed
Add a recommendation category query for local user input and check Apache file upload
1 parent 378db7d commit b6a6ed5

File tree

2 files changed

+125
-0
lines changed

2 files changed

+125
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/**
2+
* @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.
5+
* @kind path-problem
6+
* @id java/thread-resource-abuse
7+
* @problem.severity recommendation
8+
* @tags security
9+
* external/cwe/cwe-400
10+
*/
11+
12+
import java
13+
import ThreadPauseSink
14+
import semmle.code.java.dataflow.FlowSources
15+
import DataFlow::PathGraph
16+
17+
/** The `getInitParameter` method of servlet or JSF. */
18+
class GetInitParameter extends Method {
19+
GetInitParameter() {
20+
(
21+
this.getDeclaringType()
22+
.getASupertype*()
23+
.hasQualifiedName(["javax.servlet", "jakarta.servlet"],
24+
["FilterConfig", "Registration", "ServletConfig", "ServletContext"]) or
25+
this.getDeclaringType()
26+
.getASupertype*()
27+
.hasQualifiedName(["javax.faces.context", "jakarta.faces.context"], "ExternalContext")
28+
) and
29+
this.getName() = "getInitParameter"
30+
}
31+
}
32+
33+
/** An access to the `getInitParameter` method. */
34+
class GetInitParameterAccess extends MethodAccess {
35+
GetInitParameterAccess() { this.getMethod() instanceof GetInitParameter }
36+
}
37+
38+
/* Init parameter input of a Java EE web application. */
39+
class InitParameterInput extends LocalUserInput {
40+
InitParameterInput() { this.asExpr() instanceof GetInitParameterAccess }
41+
}
42+
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+
55+
/** Taint configuration of uncontrolled thread resource consumption from local user input. */
56+
class ThreadResourceAbuse extends TaintTracking::Configuration {
57+
ThreadResourceAbuse() { this = "ThreadResourceAbuse" }
58+
59+
override predicate isSource(DataFlow::Node source) { source instanceof LocalUserInput }
60+
61+
override predicate isSink(DataFlow::Node sink) { sink instanceof PauseThreadSink }
62+
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+
)
91+
}
92+
93+
override predicate isSanitizer(DataFlow::Node node) {
94+
exists(
95+
MethodAccess ma // Math.min(sleepTime, MAX_INTERVAL)
96+
|
97+
ma.getMethod().hasQualifiedName("java.lang", "Math", "min") and
98+
node.asExpr() = ma.getAnArgument()
99+
)
100+
}
101+
102+
override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) {
103+
guard instanceof LessThanSanitizer // if (sleepTime > 0 && sleepTime < 5000) { ... }
104+
}
105+
}
106+
107+
from DataFlow::PathNode source, DataFlow::PathNode sink, ThreadResourceAbuse conf
108+
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"

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ class ThreadResourceAbuse extends TaintTracking::Configuration {
4848
node1.asExpr() = arg and
4949
node2.asExpr() = fa
5050
)
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+
)
5165
}
5266

5367
override predicate isSanitizer(DataFlow::Node node) {

0 commit comments

Comments
 (0)