Skip to content

Commit 8ee1f8a

Browse files
committed
Java: Add missing flow step for ThreadLocal.initialValue.
1 parent 9f90549 commit 8ee1f8a

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

java/ql/lib/semmle/code/java/dataflow/FlowSteps.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ private module Frameworks {
2323
private import semmle.code.java.frameworks.InputStream
2424
private import semmle.code.java.frameworks.Properties
2525
private import semmle.code.java.frameworks.Protobuf
26+
private import semmle.code.java.frameworks.ThreadLocal
2627
private import semmle.code.java.frameworks.ratpack.RatpackExec
2728
private import semmle.code.java.frameworks.stapler.Stapler
2829
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import java
2+
private import semmle.code.java.dataflow.DataFlow
3+
private import semmle.code.java.dataflow.FlowSteps
4+
5+
/**
6+
* Holds if `cie` construct a `ThreadLocal` object with an overridden
7+
* `initialValue` method with a return value of `init`, such that `init` is the
8+
* initial value of the `ThreadLocal` object.
9+
*/
10+
private predicate threadLocalInitialValue(ClassInstanceExpr cie, Method initialValue, Expr init) {
11+
exists(RefType t, ReturnStmt ret |
12+
cie.getConstructedType().getSourceDeclaration() = t and
13+
t.getASourceSupertype+().hasQualifiedName("java.lang", "ThreadLocal") and
14+
ret.getResult() = init and
15+
ret.getEnclosingCallable() = initialValue and
16+
initialValue.hasName("initialValue") and
17+
initialValue.getDeclaringType() = t
18+
)
19+
}
20+
21+
private class ThreadLocalInitialValueStore extends AdditionalStoreStep {
22+
override predicate step(DataFlow::Node node1, DataFlow::Content c, DataFlow::Node node2) {
23+
exists(Method initialValue, Expr init |
24+
threadLocalInitialValue(_, initialValue, init) and
25+
node1.asExpr() = init and
26+
node2.(DataFlow::InstanceParameterNode).getCallable() = initialValue and
27+
c.(DataFlow::SyntheticFieldContent).getField() = "java.lang.ThreadLocal.value"
28+
)
29+
}
30+
}
31+
32+
private class ThreadLocalInitialValueStep extends AdditionalValueStep {
33+
override predicate step(DataFlow::Node node1, DataFlow::Node node2) {
34+
exists(ClassInstanceExpr cie, Method initialValue |
35+
threadLocalInitialValue(cie, initialValue, _) and
36+
node1.(DataFlow::InstanceParameterNode).getCallable() = initialValue and
37+
node2.asExpr() = cie
38+
)
39+
}
40+
}

java/ql/test/query-tests/security/CWE-611/DocumentBuilderTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ protected DocumentBuilder initialValue() {
129129

130130
public void disableExternalEntities2(Socket sock) throws Exception {
131131
DocumentBuilder builder = XML_DOCUMENT_BUILDER.get();
132-
builder.parse(sock.getInputStream()); // $ SPURIOUS: hasTaintFlow
132+
builder.parse(sock.getInputStream()); // safe
133133
}
134134

135135
}

0 commit comments

Comments
 (0)