Skip to content

Commit 49a7367

Browse files
committed
Fix FP from mkdirs call on exact temp directory
1 parent 787e3da commit 49a7367

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed

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

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@
1313
import java
1414
import TempDirUtils
1515
import DataFlow::PathGraph
16+
import semmle.code.java.dataflow.TaintTracking2
1617

17-
private class MethodFileSystemFileCreation extends Method {
18-
MethodFileSystemFileCreation() {
19-
this.getDeclaringType() instanceof TypeFile and
20-
this.hasName(["mkdir", "mkdirs", "createNewFile"])
21-
}
18+
abstract private class MethodFileSystemFileCreation extends Method {
19+
MethodFileSystemFileCreation() { this.getDeclaringType() instanceof TypeFile }
20+
}
21+
22+
private class MethodFileDirectoryCreation extends MethodFileSystemFileCreation {
23+
MethodFileDirectoryCreation() { this.hasName(["mkdir", "mkdirs"]) }
24+
}
25+
26+
private class MethodFileFileCreation extends MethodFileSystemFileCreation {
27+
MethodFileFileCreation() { this.hasName(["createNewFile"]) }
2228
}
2329

2430
abstract private class FileCreationSink extends DataFlow::Node { }
@@ -113,7 +119,10 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf
113119
isAdditionalFileTaintStep(node1, node2)
114120
}
115121

116-
override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink }
122+
override predicate isSink(DataFlow::Node sink) {
123+
sink instanceof FileCreationSink and
124+
exists(TempDirSystemGetPropertyDirectlyToMkdirConfig config | not config.hasFlowTo(sink))
125+
}
117126

118127
override predicate isSanitizer(DataFlow::Node sanitizer) {
119128
exists(FilesSanitizingCreationMethodAccess sanitisingMethodAccess |
@@ -122,6 +131,42 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf
122131
}
123132
}
124133

134+
/**
135+
* Configuration that tracks calls to to `mkdir` or `mkdirs` that are are directly on the temp directory system property.
136+
* Examples:
137+
* - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdir();`
138+
* - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdirs();`
139+
*
140+
* These are examples of code that is simply verifying that the temp directory exists.
141+
* As such, this code pattern is filtered out as an explicit vulnerability in
142+
* `TempDirSystemGetPropertyToCreateConfig::isSink`.
143+
*/
144+
private class TempDirSystemGetPropertyDirectlyToMkdirConfig extends TaintTracking2::Configuration {
145+
TempDirSystemGetPropertyDirectlyToMkdirConfig() {
146+
this = "TempDirSystemGetPropertyDirectlyToMkdirConfig"
147+
}
148+
149+
override predicate isSource(DataFlow::Node node) {
150+
exists(
151+
MethodAccessSystemGetPropertyTempDirTainted propertyGetMethodAccess, DataFlow::Node callSite
152+
|
153+
DataFlow::localFlow(DataFlow::exprNode(propertyGetMethodAccess), callSite)
154+
|
155+
isFileConstructorArgument(callSite.asExpr(), node.asExpr(), 1)
156+
)
157+
}
158+
159+
override predicate isSink(DataFlow::Node node) {
160+
exists(MethodAccess ma | ma.getMethod() instanceof MethodFileDirectoryCreation |
161+
ma.getQualifier() = node.asExpr()
162+
)
163+
}
164+
165+
override predicate isSanitizer(DataFlow::Node sanitizer) {
166+
isFileConstructorArgument(sanitizer.asExpr(), _, _)
167+
}
168+
}
169+
125170
//
126171
// Begin configuration for tracking single-method calls that are vulnerable.
127172
//

java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,12 @@ class MethodFileCreateTempFile extends Method {
4646
/**
4747
* Holds if `expDest` is some constructor call `new java.io.File(x)` and `expSource` is `x`.
4848
*/
49-
private predicate isFileConstructorArgument(Expr expSource, Expr exprDest) {
49+
predicate isFileConstructorArgument(Expr expSource, Expr exprDest, int paramCount) {
5050
exists(ConstructorCall construtorCall |
5151
construtorCall.getConstructedType() instanceof TypeFile and
5252
construtorCall.getArgument(0) = expSource and
53-
construtorCall = exprDest
53+
construtorCall = exprDest and
54+
construtorCall.getConstructor().getNumberOfParameters() = paramCount
5455
)
5556
}
5657

@@ -77,7 +78,7 @@ private predicate isTaintPropagatingFileTransformation(Expr expSource, Expr expr
7778
* For example, `taintedFile.getCanonicalFile()` is itself tainted.
7879
*/
7980
predicate isAdditionalFileTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
80-
isFileConstructorArgument(node1.asExpr(), node2.asExpr()) or
81+
isFileConstructorArgument(node1.asExpr(), node2.asExpr(), _) or
8182
isTaintPropagatingFileTransformation(node1.asExpr(), node2.asExpr())
8283
}
8384

java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,14 @@ void safeFileCreationWithPermissions() throws IOException {
269269
tempFile.setReadable(false, false);
270270
tempFile.setReadable(true, true);
271271
}
272+
273+
void notVulnerableCreateOnSystemPropertyDir() throws IOException {
274+
File tempDir = new File(System.getProperty("java.io.tmpdir"));
275+
tempDir.mkdir();
276+
}
277+
278+
void notVulnerableCreateOnSystemPropertyDirs() throws IOException {
279+
File tempDir = new File(System.getProperty("java.io.tmpdir"));
280+
tempDir.mkdirs();
281+
}
272282
}

0 commit comments

Comments
 (0)