From 3a15678b1ef23b012ac807116256a884c74295d1 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Fri, 2 Oct 2020 00:51:47 -0400 Subject: [PATCH 01/39] Java: CWE-200: Temp directory local information disclosure vulnerability --- java/ql/lib/semmle/code/java/JDK.qll | 6 +- java/ql/lib/semmle/code/java/StringFormat.qll | 2 +- .../frameworks/javaee/ejb/EJBRestrictions.qll | 2 +- .../code/java/security/FileWritable.qll | 2 +- .../TempDirLocalInformationDisclosure1.ql | 72 +++++++++++++++++++ .../TempDirLocalInformationDisclosure2.ql | 48 +++++++++++++ .../src/Security/CWE/CWE-200/TempDirUtils.qll | 46 ++++++++++++ .../security/CWE-200/semmle/tests/Files.java | 22 ++++++ .../TempDirLocalInformationDisclosure1.qlref | 1 + .../TempDirLocalInformationDisclosure2.qlref | 1 + .../security/CWE-200/semmle/tests/Test.java | 50 +++++++++++++ 11 files changed, 246 insertions(+), 6 deletions(-) create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/Files.java create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.qlref create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.qlref create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll index e497740a489c..b070ebb532a0 100644 --- a/java/ql/lib/semmle/code/java/JDK.qll +++ b/java/ql/lib/semmle/code/java/JDK.qll @@ -236,14 +236,14 @@ class MethodSystemGetProperty extends Method { } /** - * An access to a method named `getProperty` on class `java.lang.System`. + * Any method access to a method named `getProperty` on class `java.lang.System`. */ class MethodAccessSystemGetProperty extends MethodAccess { MethodAccessSystemGetProperty() { this.getMethod() instanceof MethodSystemGetProperty } /** - * Holds if this call has a compile-time constant first argument with the value `propertyName`. - * For example: `System.getProperty("user.dir")`. + * Holds true if this is a compile-time constant call for the specified `propertyName`. + * Eg. `System.getProperty("user.dir")`. */ predicate hasCompileTimeConstantGetPropertyName(string propertyName) { this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = propertyName diff --git a/java/ql/lib/semmle/code/java/StringFormat.qll b/java/ql/lib/semmle/code/java/StringFormat.qll index 2938f5255fad..bfc893ab7566 100644 --- a/java/ql/lib/semmle/code/java/StringFormat.qll +++ b/java/ql/lib/semmle/code/java/StringFormat.qll @@ -325,7 +325,7 @@ private predicate formatStringValue(Expr e, string fmtvalue) { or exists(Field f | e = f.getAnAccess() and - f.getDeclaringType().hasQualifiedName("java.io", "File") and + f.getDeclaringType() instanceof TypeFile and fmtvalue = "x" // dummy value | f.hasName("pathSeparator") or diff --git a/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll b/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll index c62b72ab9fc3..67c66d6d8173 100644 --- a/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll +++ b/java/ql/lib/semmle/code/java/frameworks/javaee/ejb/EJBRestrictions.qll @@ -244,7 +244,7 @@ class SecurityManagerClass extends Class { /** A class involving file input or output. */ class FileInputOutputClass extends Class { FileInputOutputClass() { - this.hasQualifiedName("java.io", "File") or + this instanceof TypeFile or this.hasQualifiedName("java.io", "FileDescriptor") or this.hasQualifiedName("java.io", "FileInputStream") or this.hasQualifiedName("java.io", "FileOutputStream") or diff --git a/java/ql/lib/semmle/code/java/security/FileWritable.qll b/java/ql/lib/semmle/code/java/security/FileWritable.qll index bd8329647da5..09a9e37fb9b2 100644 --- a/java/ql/lib/semmle/code/java/security/FileWritable.qll +++ b/java/ql/lib/semmle/code/java/security/FileWritable.qll @@ -67,7 +67,7 @@ private VarAccess getFileForPathConversion(Expr pathExpr) { fileToPath = pathExpr and result = fileToPath.getQualifier() and fileToPath.getMethod().hasName("toPath") and - fileToPath.getMethod().getDeclaringType().hasQualifiedName("java.io", "File") + fileToPath.getMethod().getDeclaringType() instanceof TypeFile ) or // Look for the pattern `Paths.get(file.get*Path())` for converting between a `File` and a `Path`. diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql new file mode 100644 index 000000000000..9790d13b4484 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql @@ -0,0 +1,72 @@ +/** + * @name Temporary Directory Local information disclosure + * @description Detect local information disclosure via the java temporary directory + * @kind problem + * @problem.severity warning + * @precision very-high + * @id java/local-information-disclosure + * @tags security + * external/cwe/cwe-200 + */ + +import TempDirUtils + +/** + * All `java.io.File::createTempFile` methods. + */ +class MethodFileCreateTempFile extends Method { + MethodFileCreateTempFile() { + this.getDeclaringType() instanceof TypeFile and + this.hasName("createTempFile") + } +} + +class TempDirSystemGetPropertyToAnyConfig extends TaintTracking::Configuration { + TempDirSystemGetPropertyToAnyConfig() { this = "TempDirSystemGetPropertyToAnyConfig" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof MethodAccessSystemGetPropertyTempDir + } + + override predicate isSink(DataFlow::Node source) { any() } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + isAdditionalFileTaintStep(node1, node2) + } +} + +abstract class MethodAccessInsecureFileCreation extends MethodAccess { } + +/** + * Insecure calls to `java.io.File::createTempFile`. + */ +class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCreation { + MethodAccessInsecureFileCreateTempFile() { + this.getMethod() instanceof MethodFileCreateTempFile and + ( + this.getNumArgument() = 2 or + getArgument(2) instanceof NullLiteral or + // There exists a flow from the 'java.io.tmpdir' system property to this argument + exists(TempDirSystemGetPropertyToAnyConfig config | + config.hasFlowTo(DataFlow::exprNode(getArgument(2))) + ) + ) + } +} + +class MethodGuavaFilesCreateTempFile extends Method { + MethodGuavaFilesCreateTempFile() { + getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and + hasName("createTempDir") + } +} + +class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureFileCreation { + MethodAccessInsecureGuavaFilesCreateTempFile() { + getMethod() instanceof MethodGuavaFilesCreateTempFile + } +} + +from MethodAccessInsecureFileCreation methodAccess +select methodAccess, + "Local information disclosure vulnerability due to use of file or directory readable by other local users." diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql new file mode 100644 index 000000000000..9a54439701b5 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql @@ -0,0 +1,48 @@ +/** + * @name Temporary Directory Local information disclosure + * @description Detect local information disclosure via the java temporary directory + * @kind path-problem + * @problem.severity warning + * @precision very-high + * @id java/local-information-disclosure + * @tags security + * external/cwe/cwe-200 + */ + +import TempDirUtils +import DataFlow::PathGraph + +private class MethodFileSystemCreation extends Method { + MethodFileSystemCreation() { + getDeclaringType() instanceof TypeFile and + ( + hasName("mkdir") or + hasName("createNewFile") + ) + } +} + +private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Configuration { + TempDirSystemGetPropertyToCreateConfig() { this = "TempDirSystemGetPropertyToCreateConfig" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof MethodAccessSystemGetPropertyTempDir + } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + isAdditionalFileTaintStep(node1, node2) + } + + override predicate isSink(DataFlow::Node sink) { + exists (MethodAccess ma | + ma.getMethod() instanceof MethodFileSystemCreation and + ma.getQualifier() = sink.asExpr() + ) + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, TempDirSystemGetPropertyToCreateConfig conf +where conf.hasFlowPath(source, sink) +select source.getNode(), source, sink, + "Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users.", source.getNode(), + "system temp directory" diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll new file mode 100644 index 000000000000..3b0f3dcc760e --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -0,0 +1,46 @@ +import java +import semmle.code.java.dataflow.FlowSources + +class MethodAccessSystemGetPropertyTempDir extends MethodAccessSystemGetProperty { + MethodAccessSystemGetPropertyTempDir() { this.hasCompileTimeConstantGetPropertyName("java.io.tmpdir") } +} + +/** + * Find dataflow from the temp directory system property to the `File` constructor. + * Examples: + * - `new File(System.getProperty("java.io.tmpdir"))` + * - `new File(new File(System.getProperty("java.io.tmpdir")), "/child")` + */ +private predicate isTaintedFileCreation(Expr expSource, Expr exprDest) { + exists(ConstructorCall construtorCall | + construtorCall.getConstructedType() instanceof TypeFile and + construtorCall.getArgument(0) = expSource and + construtorCall = exprDest + ) +} + +/** + * Any `File` methods that + */ +private class TaintFollowingFileMethod extends Method { + TaintFollowingFileMethod() { + getDeclaringType() instanceof TypeFile and + ( + hasName("getAbsoluteFile") or + hasName("getCanonicalFile") + ) + } +} + +private predicate isTaintFollowingFileTransformation(Expr expSource, Expr exprDest) { + exists(MethodAccess fileMethodAccess | + fileMethodAccess.getMethod() instanceof TaintFollowingFileMethod and + fileMethodAccess.getQualifier() = expSource and + fileMethodAccess = exprDest + ) +} + +predicate isAdditionalFileTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + isTaintedFileCreation(node1.asExpr(), node2.asExpr()) or + isTaintFollowingFileTransformation(node1.asExpr(), node2.asExpr()) +} diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Files.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Files.java new file mode 100644 index 000000000000..cc8c1a736adf --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Files.java @@ -0,0 +1,22 @@ +package com.google.common.io; + +import java.io.File; + +public class Files { + /** Maximum loop count when creating temp directories. */ + private static final int TEMP_DIR_ATTEMPTS = 10000; + + public static File createTempDir() { + File baseDir = new File(System.getProperty("java.io.tmpdir")); + String baseName = System.currentTimeMillis() + "-"; + + for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) { + File tempDir = new File(baseDir, baseName + counter); + if (tempDir.mkdir()) { + return tempDir; + } + } + throw new IllegalStateException("Failed to create directory within " + TEMP_DIR_ATTEMPTS + " attempts (tried " + + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')'); + } +} diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.qlref new file mode 100644 index 000000000000..a241deca1e28 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.qlref new file mode 100644 index 000000000000..58e4ce8d5be3 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java new file mode 100644 index 000000000000..06650fec7337 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -0,0 +1,50 @@ + +import java.io.File; +import com.google.common.io.Files; + +public class Test { + + void vulnerableFileCreateTempFile() { + File temp = File.createTempFile("random", "file"); + } + + void vulnerableFileCreateTempFileNull() { + File temp = File.createTempFile("random", "file", null); + } + + void vulnerableFileCreateTempFileTainted() { + File tempDir = new File(System.getProperty("java.io.tmpdir")); + File temp = File.createTempFile("random", "file", tempDir); + } + + void vulnerableFileCreateTempFileChildTainted() { + File tempDirChild = new File(new File(System.getProperty("java.io.tmpdir")), "/child"); + File temp = File.createTempFile("random", "file", tempDirChild); + } + + void vulnerableFileCreateTempFileCanonical() { + File tempDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile(); + File temp = File.createTempFile("random", "file", tempDir); + } + + void vulnerableFileCreateTempFileAbsolute() { + File tempDir = new File(System.getProperty("java.io.tmpdir")).getAbsoluteFile(); + File temp = File.createTempFile("random", "file", tempDir); + } + + void safeFileCreateTempFileTainted() { + /* Creating a temporary directoy in the current user directory is not a vulnerability. */ + File currentDirectory = new File(System.getProperty("user.dir")); + File temp = File.createTempFile("random", "file", currentDirectory); + } + + void vulnerableGuavaFilesCreateTempDir() { + File tempDir = Files.createTempDir(); + } + + void vulnerableFileCreateTempFileMkdirTainted() { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + tempDirChild.mkdir(); + } + +} From cf0ed8157543340340124b92db7c1ca49460a6d8 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 13 Oct 2020 20:42:09 -0400 Subject: [PATCH 02/39] Add TempDir taint tracking for Files.write --- .../TempDirLocalInformationDisclosure2.ql | 40 +++++++++++++++---- .../security/CWE-200/semmle/tests/Test.java | 18 ++++++++- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql index 9a54439701b5..9ae79bf359e4 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql @@ -12,8 +12,8 @@ import TempDirUtils import DataFlow::PathGraph -private class MethodFileSystemCreation extends Method { - MethodFileSystemCreation() { +private class MethodFileSystemFileCreation extends Method { + MethodFileSystemFileCreation() { getDeclaringType() instanceof TypeFile and ( hasName("mkdir") or @@ -22,6 +22,33 @@ private class MethodFileSystemCreation extends Method { } } +private class MethodFilesSystemFileCreation extends Method { + MethodFilesSystemFileCreation() { + getDeclaringType().hasQualifiedName("java.nio.file", "Files") and + hasName("write") + } +} + +private abstract class FileCreationSink extends DataFlow::Node {} + +private class FileFileCreationSink extends FileCreationSink { + FileFileCreationSink() { + exists(MethodAccess ma | + ma.getMethod() instanceof MethodFileSystemFileCreation and + ma.getQualifier() = this.asExpr() + ) + } +} + +private class FilesFileCreationSink extends FileCreationSink { + FilesFileCreationSink() { + exists(MethodAccess ma | + ma.getMethod() instanceof MethodFilesSystemFileCreation and + ma.getArgument(0) = this.asExpr() + ) + } +} + private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Configuration { TempDirSystemGetPropertyToCreateConfig() { this = "TempDirSystemGetPropertyToCreateConfig" } @@ -34,15 +61,12 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf } override predicate isSink(DataFlow::Node sink) { - exists (MethodAccess ma | - ma.getMethod() instanceof MethodFileSystemCreation and - ma.getQualifier() = sink.asExpr() - ) + sink instanceof FileCreationSink } } from DataFlow::PathNode source, DataFlow::PathNode sink, TempDirSystemGetPropertyToCreateConfig conf where conf.hasFlowPath(source, sink) select source.getNode(), source, sink, - "Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users.", source.getNode(), - "system temp directory" + "Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users.", + source.getNode(), "system temp directory" diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java index 06650fec7337..642aace8f6c6 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -1,6 +1,9 @@ +import java.util.Arrays; import java.io.File; -import com.google.common.io.Files; +import java.nio.file.Files; +import java.nio.charset.StandardCharsets; +import java.nio.file.StandardOpenOption; public class Test { @@ -39,12 +42,23 @@ void safeFileCreateTempFileTainted() { } void vulnerableGuavaFilesCreateTempDir() { - File tempDir = Files.createTempDir(); + File tempDir = com.google.common.io.Files.createTempDir(); } void vulnerableFileCreateTempFileMkdirTainted() { File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); tempDirChild.mkdir(); } + + void vulnerableFileCreateTempFilesWrite1() { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + Files.write(tempDirChild.toPath(), Arrays.asList("secret"), StandardCharsets.UTF_8, StandardOpenOption.CREATE); + } + void vulnerableFileCreateTempFilesWrite2() { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + String secret = "secret"; + byte[] byteArrray = secret.getBytes(); + Files.write(tempDirChild.toPath(), byteArrray, StandardOpenOption.CREATE); + } } From ecad7534ae7b2f6740847c431a0aa17ef02c9012 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 8 Dec 2020 15:31:18 -0500 Subject: [PATCH 03/39] Add mkdirs check --- .../CWE/CWE-200/TempDirLocalInformationDisclosure2.ql | 2 +- .../test/query-tests/security/CWE-200/semmle/tests/Test.java | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql index 9ae79bf359e4..8f242ab50f4c 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql @@ -16,7 +16,7 @@ private class MethodFileSystemFileCreation extends Method { MethodFileSystemFileCreation() { getDeclaringType() instanceof TypeFile and ( - hasName("mkdir") or + hasName(["mkdir", "mkdirs"]) or hasName("createNewFile") ) } diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java index 642aace8f6c6..798d6d9a85f0 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -50,6 +50,11 @@ void vulnerableFileCreateTempFileMkdirTainted() { tempDirChild.mkdir(); } + void vulnerableFileCreateTempFileMkdirsTainted() { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + tempDirChild.mkdir(); + } + void vulnerableFileCreateTempFilesWrite1() { File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); Files.write(tempDirChild.toPath(), Arrays.asList("secret"), StandardCharsets.UTF_8, StandardOpenOption.CREATE); From bc12e994b0d62398e95b889b1d6bbbf53916416f Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Fri, 1 Jan 2021 19:32:32 -0500 Subject: [PATCH 04/39] Add `java.nio.file.Files` API checks --- .../TempDirLocalInformationDisclosure2.ql | 27 ++++++------ ...empDirLocalInformationDisclosure1.expected | 7 +++ ...empDirLocalInformationDisclosure2.expected | 43 +++++++++++++++++++ .../security/CWE-200/semmle/tests/Test.java | 43 +++++++++++++++++-- 4 files changed, 103 insertions(+), 17 deletions(-) create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.expected create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.expected diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql index 8f242ab50f4c..7746a9230f67 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql @@ -22,14 +22,7 @@ private class MethodFileSystemFileCreation extends Method { } } -private class MethodFilesSystemFileCreation extends Method { - MethodFilesSystemFileCreation() { - getDeclaringType().hasQualifiedName("java.nio.file", "Files") and - hasName("write") - } -} - -private abstract class FileCreationSink extends DataFlow::Node {} +abstract private class FileCreationSink extends DataFlow::Node { } private class FileFileCreationSink extends FileCreationSink { FileFileCreationSink() { @@ -42,9 +35,17 @@ private class FileFileCreationSink extends FileCreationSink { private class FilesFileCreationSink extends FileCreationSink { FilesFileCreationSink() { - exists(MethodAccess ma | - ma.getMethod() instanceof MethodFilesSystemFileCreation and - ma.getArgument(0) = this.asExpr() + exists(FilesVulnerableCreationMethodAccess ma | ma.getArgument(0) = this.asExpr()) + } +} + +private class FilesVulnerableCreationMethodAccess extends MethodAccess { + FilesVulnerableCreationMethodAccess() { + getMethod().getDeclaringType().hasQualifiedName("java.nio.file", "Files") and + ( + getMethod().hasName(["write", "newBufferedWriter", "newOutputStream"]) + or + getMethod().hasName(["createFile", "createDirectory", "createDirectories"]) and getNumArgument() = 1 ) } } @@ -60,9 +61,7 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf isAdditionalFileTaintStep(node1, node2) } - override predicate isSink(DataFlow::Node sink) { - sink instanceof FileCreationSink - } + override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink } } from DataFlow::PathNode source, DataFlow::PathNode sink, TempDirSystemGetPropertyToCreateConfig conf diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.expected new file mode 100644 index 000000000000..50f825d9683a --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.expected @@ -0,0 +1,7 @@ +| Test.java:15:21:15:57 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | +| Test.java:19:21:19:63 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | +| Test.java:24:21:24:66 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | +| Test.java:29:21:29:71 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | +| Test.java:34:21:34:66 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | +| Test.java:39:21:39:66 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | +| Test.java:49:24:49:65 | createTempDir(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.expected new file mode 100644 index 000000000000..d094e505650d --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.expected @@ -0,0 +1,43 @@ +edges +| Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | +| Test.java:53:38:53:73 | getProperty(...) : String | Test.java:54:9:54:20 | tempDirChild | +| Test.java:58:38:58:73 | getProperty(...) : String | Test.java:59:9:59:20 | tempDirChild | +| Test.java:63:38:63:73 | getProperty(...) : String | Test.java:64:21:64:41 | toPath(...) | +| Test.java:68:38:68:73 | getProperty(...) : String | Test.java:71:21:71:41 | toPath(...) | +| Test.java:75:38:75:73 | getProperty(...) : String | Test.java:76:33:76:53 | toPath(...) | +| Test.java:80:38:80:73 | getProperty(...) : String | Test.java:81:31:81:51 | toPath(...) | +| Test.java:85:38:85:73 | getProperty(...) : String | Test.java:86:26:86:46 | toPath(...) | +| Test.java:98:38:98:73 | getProperty(...) : String | Test.java:99:31:99:51 | toPath(...) | +| Test.java:103:38:103:73 | getProperty(...) : String | Test.java:104:33:104:53 | toPath(...) | +nodes +| Files.java:10:33:10:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Files.java:15:17:15:23 | tempDir | semmle.label | tempDir | +| Test.java:53:38:53:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:54:9:54:20 | tempDirChild | semmle.label | tempDirChild | +| Test.java:58:38:58:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:59:9:59:20 | tempDirChild | semmle.label | tempDirChild | +| Test.java:63:38:63:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:64:21:64:41 | toPath(...) | semmle.label | toPath(...) | +| Test.java:68:38:68:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:71:21:71:41 | toPath(...) | semmle.label | toPath(...) | +| Test.java:75:38:75:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:76:33:76:53 | toPath(...) | semmle.label | toPath(...) | +| Test.java:80:38:80:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:81:31:81:51 | toPath(...) | semmle.label | toPath(...) | +| Test.java:85:38:85:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:86:26:86:46 | toPath(...) | semmle.label | toPath(...) | +| Test.java:98:38:98:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:99:31:99:51 | toPath(...) | semmle.label | toPath(...) | +| Test.java:103:38:103:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:104:33:104:53 | toPath(...) | semmle.label | toPath(...) | +#select +| Files.java:10:33:10:68 | getProperty(...) | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Files.java:10:33:10:68 | getProperty(...) | system temp directory | +| Test.java:53:38:53:73 | getProperty(...) | Test.java:53:38:53:73 | getProperty(...) : String | Test.java:54:9:54:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:53:38:53:73 | getProperty(...) | system temp directory | +| Test.java:58:38:58:73 | getProperty(...) | Test.java:58:38:58:73 | getProperty(...) : String | Test.java:59:9:59:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:58:38:58:73 | getProperty(...) | system temp directory | +| Test.java:63:38:63:73 | getProperty(...) | Test.java:63:38:63:73 | getProperty(...) : String | Test.java:64:21:64:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:63:38:63:73 | getProperty(...) | system temp directory | +| Test.java:68:38:68:73 | getProperty(...) | Test.java:68:38:68:73 | getProperty(...) : String | Test.java:71:21:71:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:68:38:68:73 | getProperty(...) | system temp directory | +| Test.java:75:38:75:73 | getProperty(...) | Test.java:75:38:75:73 | getProperty(...) : String | Test.java:76:33:76:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:75:38:75:73 | getProperty(...) | system temp directory | +| Test.java:80:38:80:73 | getProperty(...) | Test.java:80:38:80:73 | getProperty(...) : String | Test.java:81:31:81:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:80:38:80:73 | getProperty(...) | system temp directory | +| Test.java:85:38:85:73 | getProperty(...) | Test.java:85:38:85:73 | getProperty(...) : String | Test.java:86:26:86:46 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:85:38:85:73 | getProperty(...) | system temp directory | +| Test.java:98:38:98:73 | getProperty(...) | Test.java:98:38:98:73 | getProperty(...) : String | Test.java:99:31:99:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:98:38:98:73 | getProperty(...) | system temp directory | +| Test.java:103:38:103:73 | getProperty(...) | Test.java:103:38:103:73 | getProperty(...) : String | Test.java:104:33:104:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:103:38:103:73 | getProperty(...) | system temp directory | diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java index 798d6d9a85f0..23cefed3661f 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -1,9 +1,13 @@ import java.util.Arrays; import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.charset.StandardCharsets; import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.EnumSet; public class Test { @@ -52,18 +56,51 @@ void vulnerableFileCreateTempFileMkdirTainted() { void vulnerableFileCreateTempFileMkdirsTainted() { File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); - tempDirChild.mkdir(); + tempDirChild.mkdirs(); } void vulnerableFileCreateTempFilesWrite1() { - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); Files.write(tempDirChild.toPath(), Arrays.asList("secret"), StandardCharsets.UTF_8, StandardOpenOption.CREATE); } void vulnerableFileCreateTempFilesWrite2() { - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); String secret = "secret"; byte[] byteArrray = secret.getBytes(); Files.write(tempDirChild.toPath(), byteArrray, StandardOpenOption.CREATE); } + + void vulnerableFileCreateTempFilesNewBufferedWriter() throws IOException { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-buffered-writer.txt"); + Files.newBufferedWriter(tempDirChild.toPath()); + } + + void vulnerableFileCreateTempFilesNewOutputStream() throws IOException { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-output-stream.txt"); + Files.newOutputStream(tempDirChild.toPath()).close(); + } + + void vulnerableFileCreateTempFilesCreateFile() throws IOException { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + Files.createFile(tempDirChild.toPath()); + } + + void safeFileCreateTempFilesCreateFile() throws IOException { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + Files.createFile( + tempDirChild.toPath(), + PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)) + ); + } + + void vulnerableFileCreateDirectory() throws IOException { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); + Files.createDirectory(tempDirChild.toPath()); + } + + void vulnerableFileCreateDirectories() throws IOException { + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directories/child"); + Files.createDirectories(tempDirChild.toPath()); + } } From 13fed0e9b6c8a414dbedb6ddef5694efa13229a7 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Sat, 23 Jan 2021 18:12:56 -0500 Subject: [PATCH 05/39] Temp Dir Info Disclosure: Final pass and add documentation --- .../TempDirLocalInformationDisclosure.qhelp | 47 +++++++++++++++++++ ...lInformationDisclosureFromMethodCall.qhelp | 5 ++ ...calInformationDisclosureFromMethodCall.ql} | 6 ++- ...ormationDisclosureFromSystemProperty.qhelp | 5 ++ ...nformationDisclosureFromSystemProperty.ql} | 15 +++++- .../CWE/CWE-200/TempDirUsageSafe.java | 19 ++++++++ .../CWE/CWE-200/TempDirUsageVulnerable.java | 19 ++++++++ .../src/Security/CWE/CWE-200/TempDirUtils.qll | 30 ++++++++++-- .../TempDirLocalInformationDisclosure1.qlref | 1 - .../TempDirLocalInformationDisclosure2.qlref | 1 - ...ormationDisclosureFromMethodCall.expected} | 0 ...lInformationDisclosureFromMethodCall.qlref | 1 + ...tionDisclosureFromSystemProperty.expected} | 16 +++---- ...ormationDisclosureFromSystemProperty.qlref | 1 + .../security/CWE-200/semmle/tests/Test.java | 5 +- 15 files changed, 152 insertions(+), 19 deletions(-) create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp rename java/ql/src/Security/CWE/CWE-200/{TempDirLocalInformationDisclosure1.ql => TempDirLocalInformationDisclosureFromMethodCall.ql} (92%) create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp rename java/ql/src/Security/CWE/CWE-200/{TempDirLocalInformationDisclosure2.ql => TempDirLocalInformationDisclosureFromSystemProperty.ql} (83%) create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirUsageSafe.java create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirUsageVulnerable.java delete mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.qlref delete mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.qlref rename java/ql/test/query-tests/security/CWE-200/semmle/tests/{TempDirLocalInformationDisclosure1.expected => TempDirLocalInformationDisclosureFromMethodCall.expected} (100%) create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.qlref rename java/ql/test/query-tests/security/CWE-200/semmle/tests/{TempDirLocalInformationDisclosure2.expected => TempDirLocalInformationDisclosureFromSystemProperty.expected} (83%) create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.qlref diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp new file mode 100644 index 000000000000..2f90baf0520f --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp @@ -0,0 +1,47 @@ + + + +

Local information disclosure can occur when files/directories are written into +directories that are shared between all users on the system.

+ +

On most unix-like systems, +the system temporary directory is shared between local users. +If files/directories are created within the system temporary directory without using +APIs that explicitly set the correct file permissions, local information disclosure +can occur.

+ +

Depending upon the particular file contents exposed, this vulnerability can have a +CVSSv3.1 base score of 6.2/10.

+
+ + +

Use JDK methods that specifically protect against this vulnerability:

+
    +
  • java.nio.file.Files#createTempDirectory
  • +
  • java.nio.file.Files#createTempFile
  • +
      +Otherwise, create the file/directory by manually specificfying the expected posix file permissions. +Eg. PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)) + + + + +

      In the following example, files and directories are created with file permissions allowing other local users to read their contents.

      + + + +

      In the following example, files and directories are created with file permissions protecting their contents.

      + + + + +
    • OSWAP: Insecure Temporary File.
    • +
    • CERT: FIO00-J. Do not operate on files in shared directories + + diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp new file mode 100644 index 000000000000..41e9af9a730f --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql similarity index 92% rename from java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql rename to java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index 9790d13b4484..3e8280d55b45 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -4,9 +4,10 @@ * @kind problem * @problem.severity warning * @precision very-high - * @id java/local-information-disclosure + * @id java/local-temp-file-or-directory-information-disclosure-method * @tags security * external/cwe/cwe-200 + * external/cwe/cwe-732 */ import TempDirUtils @@ -25,7 +26,7 @@ class TempDirSystemGetPropertyToAnyConfig extends TaintTracking::Configuration { TempDirSystemGetPropertyToAnyConfig() { this = "TempDirSystemGetPropertyToAnyConfig" } override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof MethodAccessSystemGetPropertyTempDir + source.asExpr() instanceof MethodAccessSystemGetPropertyTempDirTainted } override predicate isSink(DataFlow::Node source) { any() } @@ -45,6 +46,7 @@ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCre this.getMethod() instanceof MethodFileCreateTempFile and ( this.getNumArgument() = 2 or + // Vulnerablilty exists when the last argument is `null` getArgument(2) instanceof NullLiteral or // There exists a flow from the 'java.io.tmpdir' system property to this argument exists(TempDirSystemGetPropertyToAnyConfig config | diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp new file mode 100644 index 000000000000..41e9af9a730f --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp @@ -0,0 +1,5 @@ + + + diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql similarity index 83% rename from java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql rename to java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql index 7746a9230f67..91191d5cb1fc 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql @@ -4,9 +4,10 @@ * @kind path-problem * @problem.severity warning * @precision very-high - * @id java/local-information-disclosure + * @id java/local-temp-file-or-directory-information-disclosure-path * @tags security * external/cwe/cwe-200 + * external/cwe/cwe-732 */ import TempDirUtils @@ -24,6 +25,9 @@ private class MethodFileSystemFileCreation extends Method { abstract private class FileCreationSink extends DataFlow::Node { } +/** + * Sink for tainted `File` having a file or directory creation method called on it. + */ private class FileFileCreationSink extends FileCreationSink { FileFileCreationSink() { exists(MethodAccess ma | @@ -33,12 +37,19 @@ private class FileFileCreationSink extends FileCreationSink { } } +/** + * Sink for if tained File/Path having some `Files` method called on it that creates a file or directory. + */ private class FilesFileCreationSink extends FileCreationSink { FilesFileCreationSink() { exists(FilesVulnerableCreationMethodAccess ma | ma.getArgument(0) = this.asExpr()) } } +/** + * Captures all of the vulnerable methods on `Files` that create files/directories without explicitly + * setting the permissions. + */ private class FilesVulnerableCreationMethodAccess extends MethodAccess { FilesVulnerableCreationMethodAccess() { getMethod().getDeclaringType().hasQualifiedName("java.nio.file", "Files") and @@ -54,7 +65,7 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf TempDirSystemGetPropertyToCreateConfig() { this = "TempDirSystemGetPropertyToCreateConfig" } override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof MethodAccessSystemGetPropertyTempDir + source.asExpr() instanceof MethodAccessSystemGetPropertyTempDirTainted } override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUsageSafe.java b/java/ql/src/Security/CWE/CWE-200/TempDirUsageSafe.java new file mode 100644 index 000000000000..96227d63d454 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUsageSafe.java @@ -0,0 +1,19 @@ +import java.nio.file.Files; +import java.nio.file.attribute.PosixFilePermission; +import java.nio.file.attribute.PosixFilePermissions; +import java.util.EnumSet; + +public class TempDirUsageSafe { + void exampleSafe() throws IOException { + Path temp1 = Files.createTempFile("random", ".txt"); // GOOD: File has permissions `-rw-------` + + Path temp2 = Files.createTempDirectory("random-directory"); // GOOD: File has permissions `drwx------` + + File tempDirChildFile = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + Files.createFile( + tempDirChildFile.toPath(), + tempDirChild.toPath(), + PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)) + ); // GOOD: Good has permissions `-rw-------` + } +} diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUsageVulnerable.java b/java/ql/src/Security/CWE/CWE-200/TempDirUsageVulnerable.java new file mode 100644 index 000000000000..a55226ad5b68 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUsageVulnerable.java @@ -0,0 +1,19 @@ +import java.io.File; + +public class TempDirUsageVulnerable { + void exampleVulnerable() { + File temp1 = File.createTempFile("random", ".txt"); // BAD: File has permissions `-rw-r--r--` + + File temp2 = File.createTempFile("random", "file", null); // BAD: File has permissions `-rw-r--r--` + + File systemTempDir = new File(System.getProperty("java.io.tmpdir")); + File temp3 = File.createTempFile("random", "file", systemTempDir); // BAD: File has permissions `-rw-r--r--` + + File tempDir = com.google.common.io.Files.createTempDir(); // BAD: CVE-2020-8908: Directory has permissions `drwxr-xr-x` + + new File(System.getProperty("java.io.tmpdir"), "/child").mkdir(); // BAD: Directory has permissions `-rw-r--r--` + + File tempDirChildFile = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + Files.createFile(tempDirChildFile.toPath()); // BAD: File has permissions `-rw-r--r--` + } +} diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index 3b0f3dcc760e..cf531a3e17ee 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -1,8 +1,32 @@ import java import semmle.code.java.dataflow.FlowSources -class MethodAccessSystemGetPropertyTempDir extends MethodAccessSystemGetProperty { - MethodAccessSystemGetPropertyTempDir() { this.hasCompileTimeConstantGetPropertyName("java.io.tmpdir") } +/** + * A method that returns a `String` or `File` that has been tainted by `System.getProperty("java.io.tmpdir")`. + */ +abstract class MethodAccessSystemGetPropertyTempDirTainted extends MethodAccess { } + +/** + * Method access `System.getProperty("java.io.tmpdir")`. + */ +private class MethodAccessSystemGetPropertyTempDir extends MethodAccessSystemGetPropertyTempDirTainted, + MethodAccessSystemGetProperty { + MethodAccessSystemGetPropertyTempDir() { + this.hasCompileTimeConstantGetPropertyName("java.io.tmpdir") + } +} + +/** + * A method call to the `org.apache.commons.io.FileUtils` methods `getTempDirectory` or `getTempDirectoryPath`. + */ +private class MethodAccessApacheFileUtilsTempDir extends MethodAccessSystemGetPropertyTempDirTainted { + MethodAccessApacheFileUtilsTempDir() { + exists(Method m | + m.getDeclaringType().hasQualifiedName("org.apache.commons.io", "FileUtils") and + m.hasName(["getTempDirectory", "getTempDirectoryPath"]) and + this.getMethod() = m + ) + } } /** @@ -20,7 +44,7 @@ private predicate isTaintedFileCreation(Expr expSource, Expr exprDest) { } /** - * Any `File` methods that + * Any `File` methods that */ private class TaintFollowingFileMethod extends Method { TaintFollowingFileMethod() { diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.qlref deleted file mode 100644 index a241deca1e28..000000000000 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-200/TempDirLocalInformationDisclosure1.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.qlref deleted file mode 100644 index 58e4ce8d5be3..000000000000 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-200/TempDirLocalInformationDisclosure2.ql \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected similarity index 100% rename from java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure1.expected rename to java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.qlref new file mode 100644 index 000000000000..9c785f79c55e --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected similarity index 83% rename from java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.expected rename to java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected index d094e505650d..770a4826c950 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure2.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected @@ -7,8 +7,8 @@ edges | Test.java:75:38:75:73 | getProperty(...) : String | Test.java:76:33:76:53 | toPath(...) | | Test.java:80:38:80:73 | getProperty(...) : String | Test.java:81:31:81:51 | toPath(...) | | Test.java:85:38:85:73 | getProperty(...) : String | Test.java:86:26:86:46 | toPath(...) | -| Test.java:98:38:98:73 | getProperty(...) : String | Test.java:99:31:99:51 | toPath(...) | -| Test.java:103:38:103:73 | getProperty(...) : String | Test.java:104:33:104:53 | toPath(...) | +| Test.java:99:38:99:73 | getProperty(...) : String | Test.java:100:31:100:51 | toPath(...) | +| Test.java:104:38:104:73 | getProperty(...) : String | Test.java:105:33:105:53 | toPath(...) | nodes | Files.java:10:33:10:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Files.java:15:17:15:23 | tempDir | semmle.label | tempDir | @@ -26,10 +26,10 @@ nodes | Test.java:81:31:81:51 | toPath(...) | semmle.label | toPath(...) | | Test.java:85:38:85:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:86:26:86:46 | toPath(...) | semmle.label | toPath(...) | -| Test.java:98:38:98:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:99:31:99:51 | toPath(...) | semmle.label | toPath(...) | -| Test.java:103:38:103:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:104:33:104:53 | toPath(...) | semmle.label | toPath(...) | +| Test.java:99:38:99:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:100:31:100:51 | toPath(...) | semmle.label | toPath(...) | +| Test.java:104:38:104:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:105:33:105:53 | toPath(...) | semmle.label | toPath(...) | #select | Files.java:10:33:10:68 | getProperty(...) | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Files.java:10:33:10:68 | getProperty(...) | system temp directory | | Test.java:53:38:53:73 | getProperty(...) | Test.java:53:38:53:73 | getProperty(...) : String | Test.java:54:9:54:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:53:38:53:73 | getProperty(...) | system temp directory | @@ -39,5 +39,5 @@ nodes | Test.java:75:38:75:73 | getProperty(...) | Test.java:75:38:75:73 | getProperty(...) : String | Test.java:76:33:76:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:75:38:75:73 | getProperty(...) | system temp directory | | Test.java:80:38:80:73 | getProperty(...) | Test.java:80:38:80:73 | getProperty(...) : String | Test.java:81:31:81:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:80:38:80:73 | getProperty(...) | system temp directory | | Test.java:85:38:85:73 | getProperty(...) | Test.java:85:38:85:73 | getProperty(...) : String | Test.java:86:26:86:46 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:85:38:85:73 | getProperty(...) | system temp directory | -| Test.java:98:38:98:73 | getProperty(...) | Test.java:98:38:98:73 | getProperty(...) : String | Test.java:99:31:99:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:98:38:98:73 | getProperty(...) | system temp directory | -| Test.java:103:38:103:73 | getProperty(...) | Test.java:103:38:103:73 | getProperty(...) : String | Test.java:104:33:104:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:103:38:103:73 | getProperty(...) | system temp directory | +| Test.java:99:38:99:73 | getProperty(...) | Test.java:99:38:99:73 | getProperty(...) : String | Test.java:100:31:100:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:99:38:99:73 | getProperty(...) | system temp directory | +| Test.java:104:38:104:73 | getProperty(...) | Test.java:104:38:104:73 | getProperty(...) : String | Test.java:105:33:105:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:104:38:104:73 | getProperty(...) | system temp directory | diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.qlref new file mode 100644 index 000000000000..9c3119da5d2f --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java index 23cefed3661f..c86476ad7636 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -87,6 +87,7 @@ void vulnerableFileCreateTempFilesCreateFile() throws IOException { } void safeFileCreateTempFilesCreateFile() throws IOException { + // Clear permissions intentions by setting the 'OWNER_READ' and 'OWNER_WRITE' permissions. File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); Files.createFile( tempDirChild.toPath(), @@ -96,11 +97,11 @@ void safeFileCreateTempFilesCreateFile() throws IOException { void vulnerableFileCreateDirectory() throws IOException { File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); - Files.createDirectory(tempDirChild.toPath()); + Files.createDirectory(tempDirChild.toPath()); // Creates with permissions 'drwxr-xr-x' } void vulnerableFileCreateDirectories() throws IOException { File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directories/child"); - Files.createDirectories(tempDirChild.toPath()); + Files.createDirectories(tempDirChild.toPath()); // Creates with permissions 'drwxr-xr-x' } } From e4c017e888d15d69823986fc34e9bd1847c6f236 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 16 Feb 2021 11:26:11 -0500 Subject: [PATCH 06/39] Apply suggestions from code review Co-authored-by: Arthur Baars --- .../CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp index 2f90baf0520f..dd94c58a9e08 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp @@ -21,9 +21,9 @@ can occur.

      • java.nio.file.Files#createTempDirectory
      • java.nio.file.Files#createTempFile
      • -
          -Otherwise, create the file/directory by manually specificfying the expected posix file permissions. -Eg. PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)) +
        +

        Otherwise, create the file/directory by manually specificfying the expected posix file permissions. +Eg. PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))

        • java.nio.file.Files#createFile
        • java.nio.file.Files#createDirectory
        • @@ -39,9 +39,10 @@ Eg. PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OW

          In the following example, files and directories are created with file permissions protecting their contents.

          +
        • OSWAP: Insecure Temporary File.
        • -
        • CERT: FIO00-J. Do not operate on files in shared directories +
        • CERT: FIO00-J. Do not operate on files in shared directories
        • From f910fd4719dcc7ba6ccd38f849861a2cb86b53c8 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 16 Feb 2021 16:39:53 -0500 Subject: [PATCH 07/39] Remove path flow tracking in 'TempDirLocalInformationDisclosureFromMethodCall' --- ...ocalInformationDisclosureFromMethodCall.ql | 45 ++++++------------- ...InformationDisclosureFromSystemProperty.ql | 14 +++++- .../src/Security/CWE/CWE-200/TempDirUtils.qll | 12 ++++- ...formationDisclosureFromMethodCall.expected | 10 ++--- ...ationDisclosureFromSystemProperty.expected | 16 +++++++ 5 files changed, 57 insertions(+), 40 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index 3e8280d55b45..da6e3698bf07 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -12,32 +12,13 @@ import TempDirUtils -/** - * All `java.io.File::createTempFile` methods. - */ -class MethodFileCreateTempFile extends Method { - MethodFileCreateTempFile() { - this.getDeclaringType() instanceof TypeFile and - this.hasName("createTempFile") - } +abstract class MethodAccessInsecureFileCreation extends MethodAccess { + /** + * Docstring describing the file system type (ie. file, directory, ect...) returned. + */ + abstract string getFileSystemType(); } -class TempDirSystemGetPropertyToAnyConfig extends TaintTracking::Configuration { - TempDirSystemGetPropertyToAnyConfig() { this = "TempDirSystemGetPropertyToAnyConfig" } - - override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof MethodAccessSystemGetPropertyTempDirTainted - } - - override predicate isSink(DataFlow::Node source) { any() } - - override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalFileTaintStep(node1, node2) - } -} - -abstract class MethodAccessInsecureFileCreation extends MethodAccess { } - /** * Insecure calls to `java.io.File::createTempFile`. */ @@ -45,15 +26,14 @@ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCre MethodAccessInsecureFileCreateTempFile() { this.getMethod() instanceof MethodFileCreateTempFile and ( - this.getNumArgument() = 2 or + this.getNumArgument() = 2 + or // Vulnerablilty exists when the last argument is `null` - getArgument(2) instanceof NullLiteral or - // There exists a flow from the 'java.io.tmpdir' system property to this argument - exists(TempDirSystemGetPropertyToAnyConfig config | - config.hasFlowTo(DataFlow::exprNode(getArgument(2))) - ) + getArgument(2) instanceof NullLiteral ) } + + override string getFileSystemType() { result = "file" } } class MethodGuavaFilesCreateTempFile extends Method { @@ -67,8 +47,11 @@ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureF MethodAccessInsecureGuavaFilesCreateTempFile() { getMethod() instanceof MethodGuavaFilesCreateTempFile } + + override string getFileSystemType() { result = "directory" } } from MethodAccessInsecureFileCreation methodAccess select methodAccess, - "Local information disclosure vulnerability due to use of file or directory readable by other local users." + "Local information disclosure vulnerability due to use of " + methodAccess.getFileSystemType() + + " readable by other local users." diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql index 91191d5cb1fc..91f2bb3ebada 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql @@ -56,7 +56,19 @@ private class FilesVulnerableCreationMethodAccess extends MethodAccess { ( getMethod().hasName(["write", "newBufferedWriter", "newOutputStream"]) or - getMethod().hasName(["createFile", "createDirectory", "createDirectories"]) and getNumArgument() = 1 + getMethod().hasName(["createFile", "createDirectory", "createDirectories"]) and + getNumArgument() = 1 + ) + } +} + +/** + * A call to `java.io.File::createTempFile` where the the system temp dir sinks to the last argument. + */ +private class FileCreateTempFileSink extends FileCreationSink { + FileCreateTempFileSink() { + exists(MethodAccess ma | + ma.getMethod() instanceof MethodFileCreateTempFile and ma.getArgument(2) = this.asExpr() ) } } diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index cf531a3e17ee..cf829de860f5 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -29,6 +29,16 @@ private class MethodAccessApacheFileUtilsTempDir extends MethodAccessSystemGetPr } } +/** + * All `java.io.File::createTempFile` methods. + */ +class MethodFileCreateTempFile extends Method { + MethodFileCreateTempFile() { + this.getDeclaringType() instanceof TypeFile and + this.hasName("createTempFile") + } +} + /** * Find dataflow from the temp directory system property to the `File` constructor. * Examples: @@ -44,7 +54,7 @@ private predicate isTaintedFileCreation(Expr expSource, Expr exprDest) { } /** - * Any `File` methods that + * Any `File` methods where the temporary directory is still part of the root path. */ private class TaintFollowingFileMethod extends Method { TaintFollowingFileMethod() { diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected index 50f825d9683a..d58eb1544168 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected @@ -1,7 +1,3 @@ -| Test.java:15:21:15:57 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | -| Test.java:19:21:19:63 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | -| Test.java:24:21:24:66 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | -| Test.java:29:21:29:71 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | -| Test.java:34:21:34:66 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | -| Test.java:39:21:39:66 | createTempFile(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | -| Test.java:49:24:49:65 | createTempDir(...) | Local information disclosure vulnerability due to use of file or directory readable by other local users. | +| Test.java:15:21:15:57 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | +| Test.java:19:21:19:63 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | +| Test.java:49:24:49:65 | createTempDir(...) | Local information disclosure vulnerability due to use of directory readable by other local users. | diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected index 770a4826c950..d71d23446dc9 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected @@ -1,5 +1,9 @@ edges | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | +| Test.java:23:33:23:68 | getProperty(...) : String | Test.java:24:59:24:65 | tempDir | +| Test.java:28:47:28:82 | getProperty(...) : String | Test.java:29:59:29:70 | tempDirChild | +| Test.java:33:33:33:68 | getProperty(...) : String | Test.java:34:59:34:65 | tempDir | +| Test.java:38:33:38:68 | getProperty(...) : String | Test.java:39:59:39:65 | tempDir | | Test.java:53:38:53:73 | getProperty(...) : String | Test.java:54:9:54:20 | tempDirChild | | Test.java:58:38:58:73 | getProperty(...) : String | Test.java:59:9:59:20 | tempDirChild | | Test.java:63:38:63:73 | getProperty(...) : String | Test.java:64:21:64:41 | toPath(...) | @@ -12,6 +16,14 @@ edges nodes | Files.java:10:33:10:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Files.java:15:17:15:23 | tempDir | semmle.label | tempDir | +| Test.java:23:33:23:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:24:59:24:65 | tempDir | semmle.label | tempDir | +| Test.java:28:47:28:82 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:29:59:29:70 | tempDirChild | semmle.label | tempDirChild | +| Test.java:33:33:33:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:34:59:34:65 | tempDir | semmle.label | tempDir | +| Test.java:38:33:38:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:39:59:39:65 | tempDir | semmle.label | tempDir | | Test.java:53:38:53:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:54:9:54:20 | tempDirChild | semmle.label | tempDirChild | | Test.java:58:38:58:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | @@ -32,6 +44,10 @@ nodes | Test.java:105:33:105:53 | toPath(...) | semmle.label | toPath(...) | #select | Files.java:10:33:10:68 | getProperty(...) | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Files.java:10:33:10:68 | getProperty(...) | system temp directory | +| Test.java:23:33:23:68 | getProperty(...) | Test.java:23:33:23:68 | getProperty(...) : String | Test.java:24:59:24:65 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:23:33:23:68 | getProperty(...) | system temp directory | +| Test.java:28:47:28:82 | getProperty(...) | Test.java:28:47:28:82 | getProperty(...) : String | Test.java:29:59:29:70 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:28:47:28:82 | getProperty(...) | system temp directory | +| Test.java:33:33:33:68 | getProperty(...) | Test.java:33:33:33:68 | getProperty(...) : String | Test.java:34:59:34:65 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:33:33:33:68 | getProperty(...) | system temp directory | +| Test.java:38:33:38:68 | getProperty(...) | Test.java:38:33:38:68 | getProperty(...) : String | Test.java:39:59:39:65 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:38:33:38:68 | getProperty(...) | system temp directory | | Test.java:53:38:53:73 | getProperty(...) | Test.java:53:38:53:73 | getProperty(...) : String | Test.java:54:9:54:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:53:38:53:73 | getProperty(...) | system temp directory | | Test.java:58:38:58:73 | getProperty(...) | Test.java:58:38:58:73 | getProperty(...) : String | Test.java:59:9:59:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:58:38:58:73 | getProperty(...) | system temp directory | | Test.java:63:38:63:73 | getProperty(...) | Test.java:63:38:63:73 | getProperty(...) : String | Test.java:64:21:64:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:63:38:63:73 | getProperty(...) | system temp directory | From 7929faedc005572c4bf9eb7982876cb174aa34e2 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 16 Feb 2021 16:45:13 -0500 Subject: [PATCH 08/39] Apply suggestions from code review Co-authored-by: Felicity Chapman --- .../CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp | 8 ++++---- .../TempDirLocalInformationDisclosureFromMethodCall.ql | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp index dd94c58a9e08..b76b0b5c6cf2 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp @@ -19,11 +19,11 @@ can occur.

          Use JDK methods that specifically protect against this vulnerability:

          Otherwise, create the file/directory by manually specificfying the expected posix file permissions. -Eg. PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))

          +For example: PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))

          • java.nio.file.Files#createFile
          • java.nio.file.Files#createDirectory
          • @@ -32,7 +32,7 @@ Eg. PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OW -

            In the following example, files and directories are created with file permissions allowing other local users to read their contents.

            +

            In the following example, files and directories are created with file permissions that allow other local users to read their contents.

            diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index da6e3698bf07..42c961a10962 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -1,6 +1,6 @@ /** - * @name Temporary Directory Local information disclosure - * @description Detect local information disclosure via the java temporary directory + * @name Temporary directory local information disclosure + * @description Writing information without explicit permissions to a shared temporary directory may disclose it to other users. * @kind problem * @problem.severity warning * @precision very-high From 41b5011b8198ea219732731cb4872924c2dfa8f2 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 16 Feb 2021 16:46:12 -0500 Subject: [PATCH 09/39] Apply suggestions from code review Co-authored-by: Felicity Chapman --- .../CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp index b76b0b5c6cf2..44c65efa637d 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp @@ -36,7 +36,7 @@ For example: PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePerm -

            In the following example, files and directories are created with file permissions protecting their contents.

            +

            In the following example, files and directories are created with file permissions that protect their contents.

            From f6067d28f980e1d8db1b472fa0c502932cfd4495 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Wed, 24 Feb 2021 11:36:59 -0500 Subject: [PATCH 10/39] Fix file names and formatting from PR feedback --- ...losure.qhelp => TempDirLocalInformationDisclosure.inc.qhelp} | 0 .../TempDirLocalInformationDisclosureFromMethodCall.qhelp | 2 +- .../TempDirLocalInformationDisclosureFromSystemProperty.qhelp | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename java/ql/src/Security/CWE/CWE-200/{TempDirLocalInformationDisclosure.qhelp => TempDirLocalInformationDisclosure.inc.qhelp} (100%) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp similarity index 100% rename from java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp rename to java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp index 41e9af9a730f..56b902d84d4a 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp @@ -2,4 +2,4 @@ "-//Semmle//qhelp//EN" "qhelp.dtd"> - + diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp index 41e9af9a730f..56b902d84d4a 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp @@ -2,4 +2,4 @@ "-//Semmle//qhelp//EN" "qhelp.dtd"> - + From c19f52cd04fbca929c56fe3183a8c52662ff6c82 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Thu, 25 Feb 2021 12:31:45 -0500 Subject: [PATCH 11/39] Add release notes for "Temporary Directory Local information disclosure" --- .../2021-02-25-local-temp-directory-information-disclosure.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md diff --git a/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md b/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md new file mode 100644 index 000000000000..540f29d14812 --- /dev/null +++ b/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md @@ -0,0 +1,4 @@ +lgtm,codescanning +* Two new queries, both titled "Temporary directory Local information disclosure" + (`java/local-temp-file-or-directory-information-disclosure-path`, `java/local-temp-file-or-directory-information-disclosure-method`), has been added. + This query finds uses of APIs that leak potentially sensitive information to other local users via the system temporary directory. \ No newline at end of file From 7e55c92eb4098003f85e6a7d96482acd4c52020d Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 22 Mar 2021 15:07:08 -0400 Subject: [PATCH 12/39] Apply suggestions from code review Co-authored-by: Anders Schack-Mulligen --- ...LocalInformationDisclosureFromMethodCall.ql | 3 ++- ...lInformationDisclosureFromSystemProperty.ql | 18 +++++++++--------- .../src/Security/CWE/CWE-200/TempDirUtils.qll | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index 42c961a10962..2fd5571b7685 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -10,11 +10,12 @@ * external/cwe/cwe-732 */ +import java import TempDirUtils abstract class MethodAccessInsecureFileCreation extends MethodAccess { /** - * Docstring describing the file system type (ie. file, directory, ect...) returned. + * Docstring describing the file system type (ie. file, directory, etc...) returned. */ abstract string getFileSystemType(); } diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql index 91f2bb3ebada..97c21437d14d 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql @@ -1,6 +1,6 @@ /** * @name Temporary Directory Local information disclosure - * @description Detect local information disclosure via the java temporary directory + * @description Writing information without explicit permissions to a shared temporary directory may disclose it to other users. * @kind path-problem * @problem.severity warning * @precision very-high @@ -10,16 +10,14 @@ * external/cwe/cwe-732 */ +import java import TempDirUtils import DataFlow::PathGraph private class MethodFileSystemFileCreation extends Method { MethodFileSystemFileCreation() { getDeclaringType() instanceof TypeFile and - ( - hasName(["mkdir", "mkdirs"]) or - hasName("createNewFile") - ) + hasName(["mkdir", "mkdirs", "createNewFile"]) } } @@ -52,11 +50,13 @@ private class FilesFileCreationSink extends FileCreationSink { */ private class FilesVulnerableCreationMethodAccess extends MethodAccess { FilesVulnerableCreationMethodAccess() { - getMethod().getDeclaringType().hasQualifiedName("java.nio.file", "Files") and - ( - getMethod().hasName(["write", "newBufferedWriter", "newOutputStream"]) + exists(Method m | + m = this.getMethod() and + m.getDeclaringType().hasQualifiedName("java.nio.file", "Files") + | + m.hasName(["write", "newBufferedWriter", "newOutputStream"]) or - getMethod().hasName(["createFile", "createDirectory", "createDirectories"]) and + m.hasName(["createFile", "createDirectory", "createDirectories"]) and getNumArgument() = 1 ) } diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index cf829de860f5..56d3bf00ebc4 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -30,7 +30,7 @@ private class MethodAccessApacheFileUtilsTempDir extends MethodAccessSystemGetPr } /** - * All `java.io.File::createTempFile` methods. + * A `java.io.File::createTempFile` method. */ class MethodFileCreateTempFile extends Method { MethodFileCreateTempFile() { From 66831989b71b2471e39462b0af5f584ed5832309 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 22 Mar 2021 16:40:46 -0400 Subject: [PATCH 13/39] Add QLdoc to TempDirUtils --- java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index 56d3bf00ebc4..8fc9cbacba7c 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -74,6 +74,9 @@ private predicate isTaintFollowingFileTransformation(Expr expSource, Expr exprDe ) } +/** + * Holds if the system temporary directory is still part of the root of the file path. + */ predicate isAdditionalFileTaintStep(DataFlow::Node node1, DataFlow::Node node2) { isTaintedFileCreation(node1.asExpr(), node2.asExpr()) or isTaintFollowingFileTransformation(node1.asExpr(), node2.asExpr()) From df716cbaa02cc0d0f4b989f6ffe852bf47604445 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 22 Mar 2021 16:45:46 -0400 Subject: [PATCH 14/39] Revert changes to MethodAccessSystemGetProperty --- java/ql/lib/semmle/code/java/JDK.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/ql/lib/semmle/code/java/JDK.qll b/java/ql/lib/semmle/code/java/JDK.qll index b070ebb532a0..e497740a489c 100644 --- a/java/ql/lib/semmle/code/java/JDK.qll +++ b/java/ql/lib/semmle/code/java/JDK.qll @@ -236,14 +236,14 @@ class MethodSystemGetProperty extends Method { } /** - * Any method access to a method named `getProperty` on class `java.lang.System`. + * An access to a method named `getProperty` on class `java.lang.System`. */ class MethodAccessSystemGetProperty extends MethodAccess { MethodAccessSystemGetProperty() { this.getMethod() instanceof MethodSystemGetProperty } /** - * Holds true if this is a compile-time constant call for the specified `propertyName`. - * Eg. `System.getProperty("user.dir")`. + * Holds if this call has a compile-time constant first argument with the value `propertyName`. + * For example: `System.getProperty("user.dir")`. */ predicate hasCompileTimeConstantGetPropertyName(string propertyName) { this.getArgument(0).(CompileTimeConstantExpr).getStringValue() = propertyName From cb3038568447299c1858e8951e0a605dc5eb6b06 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Thu, 8 Apr 2021 10:13:47 -0400 Subject: [PATCH 15/39] Update java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll Co-authored-by: Anders Schack-Mulligen --- java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index 8fc9cbacba7c..570d8c6b5015 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -54,7 +54,7 @@ private predicate isTaintedFileCreation(Expr expSource, Expr exprDest) { } /** - * Any `File` methods where the temporary directory is still part of the root path. + * A `File` method where the temporary directory is still part of the root path. */ private class TaintFollowingFileMethod extends Method { TaintFollowingFileMethod() { From 7e514e9ef9255a2296a3f45a59ca8ca3bf5a1260 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Thu, 8 Apr 2021 10:19:38 -0400 Subject: [PATCH 16/39] Add QLdoc and fix Compiler Errors in Tests --- .../src/Security/CWE/CWE-200/TempDirUtils.qll | 3 +++ .../security/CWE-200/semmle/tests/Test.java | 18 +++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index 570d8c6b5015..81c2d9ae5393 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -1,3 +1,6 @@ +/** + * Provides classes and predicates for reasoning about temporary file/directory creations. + */ import java import semmle.code.java.dataflow.FlowSources diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java index c86476ad7636..b87d12199c21 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -11,35 +11,35 @@ public class Test { - void vulnerableFileCreateTempFile() { + void vulnerableFileCreateTempFile() throws IOException { File temp = File.createTempFile("random", "file"); } - void vulnerableFileCreateTempFileNull() { + void vulnerableFileCreateTempFileNull() throws IOException { File temp = File.createTempFile("random", "file", null); } - void vulnerableFileCreateTempFileTainted() { + void vulnerableFileCreateTempFileTainted() throws IOException { File tempDir = new File(System.getProperty("java.io.tmpdir")); File temp = File.createTempFile("random", "file", tempDir); } - void vulnerableFileCreateTempFileChildTainted() { + void vulnerableFileCreateTempFileChildTainted() throws IOException { File tempDirChild = new File(new File(System.getProperty("java.io.tmpdir")), "/child"); File temp = File.createTempFile("random", "file", tempDirChild); } - void vulnerableFileCreateTempFileCanonical() { + void vulnerableFileCreateTempFileCanonical() throws IOException { File tempDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile(); File temp = File.createTempFile("random", "file", tempDir); } - void vulnerableFileCreateTempFileAbsolute() { + void vulnerableFileCreateTempFileAbsolute() throws IOException { File tempDir = new File(System.getProperty("java.io.tmpdir")).getAbsoluteFile(); File temp = File.createTempFile("random", "file", tempDir); } - void safeFileCreateTempFileTainted() { + void safeFileCreateTempFileTainted() throws IOException { /* Creating a temporary directoy in the current user directory is not a vulnerability. */ File currentDirectory = new File(System.getProperty("user.dir")); File temp = File.createTempFile("random", "file", currentDirectory); @@ -59,12 +59,12 @@ void vulnerableFileCreateTempFileMkdirsTainted() { tempDirChild.mkdirs(); } - void vulnerableFileCreateTempFilesWrite1() { + void vulnerableFileCreateTempFilesWrite1() throws IOException { File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); Files.write(tempDirChild.toPath(), Arrays.asList("secret"), StandardCharsets.UTF_8, StandardOpenOption.CREATE); } - void vulnerableFileCreateTempFilesWrite2() { + void vulnerableFileCreateTempFilesWrite2() throws IOException { File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); String secret = "secret"; byte[] byteArrray = secret.getBytes(); From e795823d972c0f585b55a69f273dd6bfb761f8a7 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 16 Apr 2021 11:29:59 +0100 Subject: [PATCH 17/39] Autoformat TempDirUtils.qll --- java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index 81c2d9ae5393..30522c08b616 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -1,6 +1,7 @@ /** * Provides classes and predicates for reasoning about temporary file/directory creations. */ + import java import semmle.code.java.dataflow.FlowSources From a8d25b63ac8ba523b7901207298126db9234d07e Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Fri, 16 Apr 2021 15:16:42 -0400 Subject: [PATCH 18/39] Apply suggestions from code review Co-authored-by: Chris Smowton --- ...DirLocalInformationDisclosureFromMethodCall.ql | 15 ++++++++------- ...ocalInformationDisclosureFromSystemProperty.ql | 10 +++++----- java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll | 12 +++++------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index 2fd5571b7685..ec47041da0b2 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -1,10 +1,10 @@ /** - * @name Temporary directory local information disclosure - * @description Writing information without explicit permissions to a shared temporary directory may disclose it to other users. + * @name Temporary directory local information disclosure (file creation via inherently insecure method) + * @description Creating a temporary file in the system shared temporary directory, using a method that always creates it world-readable, may disclose its contents to other users. * @kind problem * @problem.severity warning * @precision very-high - * @id java/local-temp-file-or-directory-information-disclosure-method + * @id java/local-temp-file-or-directory-information-disclosure-insecure-method * @tags security * external/cwe/cwe-200 * external/cwe/cwe-732 @@ -15,21 +15,22 @@ import TempDirUtils abstract class MethodAccessInsecureFileCreation extends MethodAccess { /** - * Docstring describing the file system type (ie. file, directory, etc...) returned. + * Gets the type of entity created (e.g. `file`, `directory`, ...). */ - abstract string getFileSystemType(); + abstract string getFileSystemEntityType(); } /** - * Insecure calls to `java.io.File::createTempFile`. + * An insecure call to `java.io.File::createTempFile`. */ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCreation { MethodAccessInsecureFileCreateTempFile() { this.getMethod() instanceof MethodFileCreateTempFile and ( + // `File.createTempFile(string, string)` always uses the default temporary directory this.getNumArgument() = 2 or - // Vulnerablilty exists when the last argument is `null` + // The default temporary directory is used when the last argument of `File.createTempFile(string, string, File)` is `null` getArgument(2) instanceof NullLiteral ) } diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql index 97c21437d14d..f36a3eff94cd 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql @@ -1,10 +1,10 @@ /** - * @name Temporary Directory Local information disclosure - * @description Writing information without explicit permissions to a shared temporary directory may disclose it to other users. + * @name Temporary directory local information disclosure (file creation without explicit mode) + * @description Creating a temporary file in the system shared temporary directory without specifying explicit access rights (mode) may disclose its contents to other users. * @kind path-problem * @problem.severity warning * @precision very-high - * @id java/local-temp-file-or-directory-information-disclosure-path + * @id java/local-temp-file-or-directory-information-disclosure-missing-mode * @tags security * external/cwe/cwe-200 * external/cwe/cwe-732 @@ -36,7 +36,7 @@ private class FileFileCreationSink extends FileCreationSink { } /** - * Sink for if tained File/Path having some `Files` method called on it that creates a file or directory. + * Sink for calling a file-creating or directory-creating `Files` method on a tainted `File` or `Path`. */ private class FilesFileCreationSink extends FileCreationSink { FilesFileCreationSink() { @@ -63,7 +63,7 @@ private class FilesVulnerableCreationMethodAccess extends MethodAccess { } /** - * A call to `java.io.File::createTempFile` where the the system temp dir sinks to the last argument. + * The temp directory argument to a call to `java.io.File::createTempFile`, treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. */ private class FileCreateTempFileSink extends FileCreationSink { FileCreateTempFileSink() { diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index 30522c08b616..fd09c84e44be 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -63,23 +63,21 @@ private predicate isTaintedFileCreation(Expr expSource, Expr exprDest) { private class TaintFollowingFileMethod extends Method { TaintFollowingFileMethod() { getDeclaringType() instanceof TypeFile and - ( - hasName("getAbsoluteFile") or - hasName("getCanonicalFile") - ) + hasName(["getAbsoluteFile", "getCanonicalFile"]) } } -private predicate isTaintFollowingFileTransformation(Expr expSource, Expr exprDest) { +private predicate isTaintPropagatingFileTransformation(Expr expSource, Expr exprDest) { exists(MethodAccess fileMethodAccess | - fileMethodAccess.getMethod() instanceof TaintFollowingFileMethod and + fileMethodAccess.getMethod() instanceof TaintPropagatingFileMethod and fileMethodAccess.getQualifier() = expSource and fileMethodAccess = exprDest ) } /** - * Holds if the system temporary directory is still part of the root of the file path. + * Holds if taint should propagate from `node1` to `node2` across some file creation or transformation operation. + * For example, `taintedFile.getCanonicalFile()` is itself tainted. */ predicate isAdditionalFileTaintStep(DataFlow::Node node1, DataFlow::Node node2) { isTaintedFileCreation(node1.asExpr(), node2.asExpr()) or From a4b5573f5328ac0a41319c7ca6dae59b4986dfa3 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 19 Apr 2021 11:54:35 -0400 Subject: [PATCH 19/39] Apply suggestions from code review Co-authored-by: Chris Smowton --- ...-02-25-local-temp-directory-information-disclosure.md | 2 +- .../CWE-200/TempDirLocalInformationDisclosure.inc.qhelp | 4 ++-- .../TempDirLocalInformationDisclosureFromMethodCall.ql | 6 ++++++ ...empDirLocalInformationDisclosureFromSystemProperty.ql | 9 +++++---- java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll | 2 +- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md b/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md index 540f29d14812..46654b8f14d8 100644 --- a/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md +++ b/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md @@ -1,4 +1,4 @@ lgtm,codescanning * Two new queries, both titled "Temporary directory Local information disclosure" (`java/local-temp-file-or-directory-information-disclosure-path`, `java/local-temp-file-or-directory-information-disclosure-method`), has been added. - This query finds uses of APIs that leak potentially sensitive information to other local users via the system temporary directory. \ No newline at end of file + These queries find uses of APIs that leak potentially sensitive information to other local users via the system temporary directory. diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp index 44c65efa637d..f54bee00b556 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp @@ -19,10 +19,10 @@ can occur.

            Use JDK methods that specifically protect against this vulnerability:

            -

            Otherwise, create the file/directory by manually specificfying the expected posix file permissions. +

            Otherwise, create the file/directory by manually specifying the expected posix file permissions. For example: PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))

            • java.nio.file.Files#createFile
            • diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index ec47041da0b2..6e2afd3b1134 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -38,6 +38,9 @@ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCre override string getFileSystemType() { result = "file" } } +/** + * The `com.google.common.io.Files.createTempDir` method. + */ class MethodGuavaFilesCreateTempFile extends Method { MethodGuavaFilesCreateTempFile() { getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and @@ -45,6 +48,9 @@ class MethodGuavaFilesCreateTempFile extends Method { } } +/** + * A call to the `com.google.common.io.Files.createTempDir` method. + */ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureFileCreation { MethodAccessInsecureGuavaFilesCreateTempFile() { getMethod() instanceof MethodGuavaFilesCreateTempFile diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql index f36a3eff94cd..45b82a2aa1ef 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql @@ -24,7 +24,7 @@ private class MethodFileSystemFileCreation extends Method { abstract private class FileCreationSink extends DataFlow::Node { } /** - * Sink for tainted `File` having a file or directory creation method called on it. + * The qualifier of a call to one of `File`'s file-creating or directory-creating methods, treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. */ private class FileFileCreationSink extends FileCreationSink { FileFileCreationSink() { @@ -36,7 +36,8 @@ private class FileFileCreationSink extends FileCreationSink { } /** - * Sink for calling a file-creating or directory-creating `Files` method on a tainted `File` or `Path`. + * The argument to + a call to one of `Files` file-creating or directory-creating methods, treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. */ private class FilesFileCreationSink extends FileCreationSink { FilesFileCreationSink() { @@ -45,8 +46,8 @@ private class FilesFileCreationSink extends FileCreationSink { } /** - * Captures all of the vulnerable methods on `Files` that create files/directories without explicitly - * setting the permissions. + * A call to a `Files` method that create files/directories without explicitly + * setting the newly-created file or directory's permissions. */ private class FilesVulnerableCreationMethodAccess extends MethodAccess { FilesVulnerableCreationMethodAccess() { diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index fd09c84e44be..dbc0cc7d1558 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -49,7 +49,7 @@ class MethodFileCreateTempFile extends Method { * - `new File(System.getProperty("java.io.tmpdir"))` * - `new File(new File(System.getProperty("java.io.tmpdir")), "/child")` */ -private predicate isTaintedFileCreation(Expr expSource, Expr exprDest) { +private predicate isFileConstructorArgument(Expr expSource, Expr exprDest) { exists(ConstructorCall construtorCall | construtorCall.getConstructedType() instanceof TypeFile and construtorCall.getArgument(0) = expSource and From f7a4aac52586f051db45cc71314da4465b31c6cf Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 20 Apr 2021 12:19:41 -0400 Subject: [PATCH 20/39] Apply suggestions from code review Co-authored-by: Chris Smowton --- .../TempDirLocalInformationDisclosure.inc.qhelp | 8 ++++---- ...TempDirLocalInformationDisclosureFromMethodCall.ql | 11 +++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp index f54bee00b556..22a4dd1427b1 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp @@ -20,14 +20,14 @@ can occur.

              Use JDK methods that specifically protect against this vulnerability:

              Otherwise, create the file/directory by manually specifying the expected posix file permissions. For example: PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))

              diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index 6e2afd3b1134..2d9836a94cea 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -13,6 +13,9 @@ import java import TempDirUtils +/** + * A MethodAccess against a method that creates a temporary file or directory in a shared temporary directory. + */ abstract class MethodAccessInsecureFileCreation extends MethodAccess { /** * Gets the type of entity created (e.g. `file`, `directory`, ...). @@ -21,7 +24,7 @@ abstract class MethodAccessInsecureFileCreation extends MethodAccess { } /** - * An insecure call to `java.io.File::createTempFile`. + * An insecure call to `java.io.File.createTempFile`. */ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCreation { MethodAccessInsecureFileCreateTempFile() { @@ -35,7 +38,7 @@ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCre ) } - override string getFileSystemType() { result = "file" } + override string getFileSystemEntityType() { result = "file" } } /** @@ -56,10 +59,10 @@ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureF getMethod() instanceof MethodGuavaFilesCreateTempFile } - override string getFileSystemType() { result = "directory" } + override string getFileSystemEntityType() { result = "directory" } } from MethodAccessInsecureFileCreation methodAccess select methodAccess, - "Local information disclosure vulnerability due to use of " + methodAccess.getFileSystemType() + + "Local information disclosure vulnerability due to use of " + methodAccess.getFileSystemEntityType() + " readable by other local users." From d5c9af31b224d7ca62985ce8d2359ab5e3b195b7 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 20 Apr 2021 13:12:05 -0400 Subject: [PATCH 21/39] Fixup documentation/code from PR feedback --- ...DirLocalInformationDisclosureFromSystemProperty.ql | 10 ++++++++-- java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll | 11 ++++------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql index 45b82a2aa1ef..267ae0de4a3c 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql @@ -36,8 +36,8 @@ private class FileFileCreationSink extends FileCreationSink { } /** - * The argument to - a call to one of `Files` file-creating or directory-creating methods, treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. + * The argument to + * a call to one of `Files` file-creating or directory-creating methods, treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. */ private class FilesFileCreationSink extends FileCreationSink { FilesFileCreationSink() { @@ -81,6 +81,12 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf source.asExpr() instanceof MethodAccessSystemGetPropertyTempDirTainted } + /** + * Find dataflow from the temp directory system property to the `File` constructor. + * Examples: + * - `new File(System.getProperty("java.io.tmpdir"))` + * - `new File(new File(System.getProperty("java.io.tmpdir")), "/child")` + */ override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { isAdditionalFileTaintStep(node1, node2) } diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index dbc0cc7d1558..0613006f71f9 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -44,10 +44,7 @@ class MethodFileCreateTempFile extends Method { } /** - * Find dataflow from the temp directory system property to the `File` constructor. - * Examples: - * - `new File(System.getProperty("java.io.tmpdir"))` - * - `new File(new File(System.getProperty("java.io.tmpdir")), "/child")` + * Holds if `expDest` is some constructor call `new java.io.File(x)` and `expSource` is `x`. */ private predicate isFileConstructorArgument(Expr expSource, Expr exprDest) { exists(ConstructorCall construtorCall | @@ -69,7 +66,7 @@ private class TaintFollowingFileMethod extends Method { private predicate isTaintPropagatingFileTransformation(Expr expSource, Expr exprDest) { exists(MethodAccess fileMethodAccess | - fileMethodAccess.getMethod() instanceof TaintPropagatingFileMethod and + fileMethodAccess.getMethod() instanceof TaintFollowingFileMethod and fileMethodAccess.getQualifier() = expSource and fileMethodAccess = exprDest ) @@ -80,6 +77,6 @@ private predicate isTaintPropagatingFileTransformation(Expr expSource, Expr expr * For example, `taintedFile.getCanonicalFile()` is itself tainted. */ predicate isAdditionalFileTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - isTaintedFileCreation(node1.asExpr(), node2.asExpr()) or - isTaintFollowingFileTransformation(node1.asExpr(), node2.asExpr()) + isFileConstructorArgument(node1.asExpr(), node2.asExpr()) or + isTaintPropagatingFileTransformation(node1.asExpr(), node2.asExpr()) } From 79db76dcf8717f11fae353bdfc37079d27b1b104 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Wed, 21 Apr 2021 18:19:12 -0400 Subject: [PATCH 22/39] Fix test failures TempDirLocalInformationDisclosureFromSystemProperty --- ...ationDisclosureFromSystemProperty.expected | 79 +++++++++++++++++-- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected index d71d23446dc9..dc3f39a8d714 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected @@ -1,46 +1,111 @@ edges +| Files.java:10:24:10:69 | new File(...) : File | Files.java:14:37:14:43 | baseDir : File | +| Files.java:10:24:10:69 | new File(...) : File | Files.java:15:17:15:23 | tempDir | +| Files.java:10:33:10:68 | getProperty(...) : String | Files.java:10:24:10:69 | new File(...) : File | +| Files.java:10:33:10:68 | getProperty(...) : String | Files.java:14:37:14:43 | baseDir : File | | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | +| Files.java:14:28:14:64 | new File(...) : File | Files.java:15:17:15:23 | tempDir | +| Files.java:14:37:14:43 | baseDir : File | Files.java:14:28:14:64 | new File(...) : File | +| Test.java:23:24:23:69 | new File(...) : File | Test.java:24:59:24:65 | tempDir | +| Test.java:23:33:23:68 | getProperty(...) : String | Test.java:23:24:23:69 | new File(...) : File | | Test.java:23:33:23:68 | getProperty(...) : String | Test.java:24:59:24:65 | tempDir | +| Test.java:28:29:28:94 | new File(...) : File | Test.java:29:59:29:70 | tempDirChild | +| Test.java:28:38:28:83 | new File(...) : File | Test.java:28:29:28:94 | new File(...) : File | +| Test.java:28:38:28:83 | new File(...) : File | Test.java:29:59:29:70 | tempDirChild | +| Test.java:28:47:28:82 | getProperty(...) : String | Test.java:28:38:28:83 | new File(...) : File | | Test.java:28:47:28:82 | getProperty(...) : String | Test.java:29:59:29:70 | tempDirChild | +| Test.java:33:24:33:69 | new File(...) : File | Test.java:34:59:34:65 | tempDir | +| Test.java:33:33:33:68 | getProperty(...) : String | Test.java:33:24:33:69 | new File(...) : File | | Test.java:33:33:33:68 | getProperty(...) : String | Test.java:34:59:34:65 | tempDir | +| Test.java:38:24:38:69 | new File(...) : File | Test.java:39:59:39:65 | tempDir | +| Test.java:38:33:38:68 | getProperty(...) : String | Test.java:38:24:38:69 | new File(...) : File | | Test.java:38:33:38:68 | getProperty(...) : String | Test.java:39:59:39:65 | tempDir | +| Test.java:53:29:53:84 | new File(...) : File | Test.java:54:9:54:20 | tempDirChild | +| Test.java:53:38:53:73 | getProperty(...) : String | Test.java:53:29:53:84 | new File(...) : File | | Test.java:53:38:53:73 | getProperty(...) : String | Test.java:54:9:54:20 | tempDirChild | +| Test.java:58:29:58:84 | new File(...) : File | Test.java:59:9:59:20 | tempDirChild | +| Test.java:58:38:58:73 | getProperty(...) : String | Test.java:58:29:58:84 | new File(...) : File | | Test.java:58:38:58:73 | getProperty(...) : String | Test.java:59:9:59:20 | tempDirChild | -| Test.java:63:38:63:73 | getProperty(...) : String | Test.java:64:21:64:41 | toPath(...) | -| Test.java:68:38:68:73 | getProperty(...) : String | Test.java:71:21:71:41 | toPath(...) | -| Test.java:75:38:75:73 | getProperty(...) : String | Test.java:76:33:76:53 | toPath(...) | -| Test.java:80:38:80:73 | getProperty(...) : String | Test.java:81:31:81:51 | toPath(...) | -| Test.java:85:38:85:73 | getProperty(...) : String | Test.java:86:26:86:46 | toPath(...) | -| Test.java:99:38:99:73 | getProperty(...) : String | Test.java:100:31:100:51 | toPath(...) | -| Test.java:104:38:104:73 | getProperty(...) : String | Test.java:105:33:105:53 | toPath(...) | +| Test.java:63:29:63:88 | new File(...) : File | Test.java:64:21:64:32 | tempDirChild : File | +| Test.java:63:38:63:73 | getProperty(...) : String | Test.java:63:29:63:88 | new File(...) : File | +| Test.java:63:38:63:73 | getProperty(...) : String | Test.java:64:21:64:32 | tempDirChild : File | +| Test.java:64:21:64:32 | tempDirChild : File | Test.java:64:21:64:41 | toPath(...) | +| Test.java:68:29:68:88 | new File(...) : File | Test.java:71:21:71:32 | tempDirChild : File | +| Test.java:68:38:68:73 | getProperty(...) : String | Test.java:68:29:68:88 | new File(...) : File | +| Test.java:68:38:68:73 | getProperty(...) : String | Test.java:71:21:71:32 | tempDirChild : File | +| Test.java:71:21:71:32 | tempDirChild : File | Test.java:71:21:71:41 | toPath(...) | +| Test.java:75:29:75:104 | new File(...) : File | Test.java:76:33:76:44 | tempDirChild : File | +| Test.java:75:38:75:73 | getProperty(...) : String | Test.java:75:29:75:104 | new File(...) : File | +| Test.java:75:38:75:73 | getProperty(...) : String | Test.java:76:33:76:44 | tempDirChild : File | +| Test.java:76:33:76:44 | tempDirChild : File | Test.java:76:33:76:53 | toPath(...) | +| Test.java:80:29:80:102 | new File(...) : File | Test.java:81:31:81:42 | tempDirChild : File | +| Test.java:80:38:80:73 | getProperty(...) : String | Test.java:80:29:80:102 | new File(...) : File | +| Test.java:80:38:80:73 | getProperty(...) : String | Test.java:81:31:81:42 | tempDirChild : File | +| Test.java:81:31:81:42 | tempDirChild : File | Test.java:81:31:81:51 | toPath(...) | +| Test.java:85:29:85:100 | new File(...) : File | Test.java:86:26:86:37 | tempDirChild : File | +| Test.java:85:38:85:73 | getProperty(...) : String | Test.java:85:29:85:100 | new File(...) : File | +| Test.java:85:38:85:73 | getProperty(...) : String | Test.java:86:26:86:37 | tempDirChild : File | +| Test.java:86:26:86:37 | tempDirChild : File | Test.java:86:26:86:46 | toPath(...) | +| Test.java:99:29:99:101 | new File(...) : File | Test.java:100:31:100:42 | tempDirChild : File | +| Test.java:99:38:99:73 | getProperty(...) : String | Test.java:99:29:99:101 | new File(...) : File | +| Test.java:99:38:99:73 | getProperty(...) : String | Test.java:100:31:100:42 | tempDirChild : File | +| Test.java:100:31:100:42 | tempDirChild : File | Test.java:100:31:100:51 | toPath(...) | +| Test.java:104:29:104:109 | new File(...) : File | Test.java:105:33:105:44 | tempDirChild : File | +| Test.java:104:38:104:73 | getProperty(...) : String | Test.java:104:29:104:109 | new File(...) : File | +| Test.java:104:38:104:73 | getProperty(...) : String | Test.java:105:33:105:44 | tempDirChild : File | +| Test.java:105:33:105:44 | tempDirChild : File | Test.java:105:33:105:53 | toPath(...) | nodes +| Files.java:10:24:10:69 | new File(...) : File | semmle.label | new File(...) : File | | Files.java:10:33:10:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Files.java:14:28:14:64 | new File(...) : File | semmle.label | new File(...) : File | +| Files.java:14:37:14:43 | baseDir : File | semmle.label | baseDir : File | | Files.java:15:17:15:23 | tempDir | semmle.label | tempDir | +| Test.java:23:24:23:69 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:23:33:23:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:24:59:24:65 | tempDir | semmle.label | tempDir | +| Test.java:28:29:28:94 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:28:38:28:83 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:28:47:28:82 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:29:59:29:70 | tempDirChild | semmle.label | tempDirChild | +| Test.java:33:24:33:69 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:33:33:33:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:34:59:34:65 | tempDir | semmle.label | tempDir | +| Test.java:38:24:38:69 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:38:33:38:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:39:59:39:65 | tempDir | semmle.label | tempDir | +| Test.java:53:29:53:84 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:53:38:53:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:54:9:54:20 | tempDirChild | semmle.label | tempDirChild | +| Test.java:58:29:58:84 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:58:38:58:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:59:9:59:20 | tempDirChild | semmle.label | tempDirChild | +| Test.java:63:29:63:88 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:63:38:63:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:64:21:64:32 | tempDirChild : File | semmle.label | tempDirChild : File | | Test.java:64:21:64:41 | toPath(...) | semmle.label | toPath(...) | +| Test.java:68:29:68:88 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:68:38:68:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:71:21:71:32 | tempDirChild : File | semmle.label | tempDirChild : File | | Test.java:71:21:71:41 | toPath(...) | semmle.label | toPath(...) | +| Test.java:75:29:75:104 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:75:38:75:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:76:33:76:44 | tempDirChild : File | semmle.label | tempDirChild : File | | Test.java:76:33:76:53 | toPath(...) | semmle.label | toPath(...) | +| Test.java:80:29:80:102 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:80:38:80:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:81:31:81:42 | tempDirChild : File | semmle.label | tempDirChild : File | | Test.java:81:31:81:51 | toPath(...) | semmle.label | toPath(...) | +| Test.java:85:29:85:100 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:85:38:85:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:86:26:86:37 | tempDirChild : File | semmle.label | tempDirChild : File | | Test.java:86:26:86:46 | toPath(...) | semmle.label | toPath(...) | +| Test.java:99:29:99:101 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:99:38:99:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:100:31:100:42 | tempDirChild : File | semmle.label | tempDirChild : File | | Test.java:100:31:100:51 | toPath(...) | semmle.label | toPath(...) | +| Test.java:104:29:104:109 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:104:38:104:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:105:33:105:44 | tempDirChild : File | semmle.label | tempDirChild : File | | Test.java:105:33:105:53 | toPath(...) | semmle.label | toPath(...) | #select | Files.java:10:33:10:68 | getProperty(...) | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Files.java:10:33:10:68 | getProperty(...) | system temp directory | From 0a621c2801565e5da810fee581de7a05918f9dea Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 26 Apr 2021 11:58:19 -0400 Subject: [PATCH 23/39] Fix the formatting in TempDirLocalInformationDisclosureFromMethodCall --- .../TempDirLocalInformationDisclosureFromMethodCall.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index 2d9836a94cea..43812530d44d 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -64,5 +64,5 @@ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureF from MethodAccessInsecureFileCreation methodAccess select methodAccess, - "Local information disclosure vulnerability due to use of " + methodAccess.getFileSystemEntityType() + - " readable by other local users." + "Local information disclosure vulnerability due to use of " + + methodAccess.getFileSystemEntityType() + " readable by other local users." From 9299c7996db0d64b81d3448f6e55172db8af05b6 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Fri, 28 Jan 2022 19:24:48 +0000 Subject: [PATCH 24/39] Add information disclosure test fix suggestions --- .../security/CWE-200/semmle/tests/Test.java | 193 ++++++++++++++++-- 1 file changed, 176 insertions(+), 17 deletions(-) diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java index b87d12199c21..44b8210e6584 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -3,6 +3,8 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.charset.StandardCharsets; import java.nio.file.StandardOpenOption; import java.nio.file.attribute.PosixFilePermission; @@ -12,96 +14,253 @@ public class Test { void vulnerableFileCreateTempFile() throws IOException { - File temp = File.createTempFile("random", "file"); + // VULNERABLE VERSION: + File tempVuln = File.createTempFile("random", "file"); + + // TO MAKE SAFE REWRITE TO: + File tempSafe = Files.createTempFile("random", "file").toFile(); } void vulnerableFileCreateTempFileNull() throws IOException { - File temp = File.createTempFile("random", "file", null); + // VULNERABLE VERSION: + File tempVuln = File.createTempFile("random", "file", null); + + // TO MAKE SAFE REWRITE TO: + File tempSafe = Files.createTempFile("random", "file").toFile(); } void vulnerableFileCreateTempFileTainted() throws IOException { + // GIVEN: File tempDir = new File(System.getProperty("java.io.tmpdir")); - File temp = File.createTempFile("random", "file", tempDir); + + // VULNERABLE VERSION: + File tempVuln = File.createTempFile("random", "file", tempDir); + + // TO MAKE SAFE REWRITE TO (v1): + File tempSafe1 = Files.createTempFile(tempDir.toPath(), "random", "file").toFile(); + + // TO MAKE SAFE REWRITE TO (v2): + File tempSafe2 = Files.createTempFile("random", "file").toFile(); } void vulnerableFileCreateTempFileChildTainted() throws IOException { + // GIVEN: File tempDirChild = new File(new File(System.getProperty("java.io.tmpdir")), "/child"); - File temp = File.createTempFile("random", "file", tempDirChild); + + // VULNERABLE VERSION: + File tempVuln = File.createTempFile("random", "file", tempDirChild); + + // TO MAKE SAFE REWRITE TO: + File tempSafe = Files.createTempFile(tempDirChild.toPath(), "random", "file").toFile(); } void vulnerableFileCreateTempFileCanonical() throws IOException { + // GIVEN: File tempDir = new File(System.getProperty("java.io.tmpdir")).getCanonicalFile(); - File temp = File.createTempFile("random", "file", tempDir); + + // VULNERABLE VERSION: + File tempVuln = File.createTempFile("random", "file", tempDir); + + // TO MAKE SAFE REWRITE TO (v1): + File tempSafe1 = Files.createTempFile(tempDir.toPath(), "random", "file").toFile(); + + // TO MAKE SAFE REWRITE TO (v2): + File tempSafe2 = Files.createTempFile("random", "file").toFile(); } void vulnerableFileCreateTempFileAbsolute() throws IOException { + // GIVEN: File tempDir = new File(System.getProperty("java.io.tmpdir")).getAbsoluteFile(); - File temp = File.createTempFile("random", "file", tempDir); + + // VULNERABLE VERSION: + File tempVuln = File.createTempFile("random", "file", tempDir); + + // TO MAKE SAFE REWRITE TO (v1): + File tempSafe1 = Files.createTempFile(tempDir.toPath(), "random", "file").toFile(); + // TO MAKE SAFE REWRITE TO (v2): + File tempSafe2 = Files.createTempFile("random", "file").toFile(); } void safeFileCreateTempFileTainted() throws IOException { - /* Creating a temporary directoy in the current user directory is not a vulnerability. */ + /* + * Creating a temporary directoy in the current user directory is not a + * vulnerability. + */ File currentDirectory = new File(System.getProperty("user.dir")); File temp = File.createTempFile("random", "file", currentDirectory); } void vulnerableGuavaFilesCreateTempDir() { + // VULNERABLE VERSION: File tempDir = com.google.common.io.Files.createTempDir(); + + // TO MAKE SAFE REWRITE TO: + File tempSafe; + try { + Files.createTempDirectory("random").toFile(); + } catch (IOException e) { + throw new RuntimeException("Failed to create temporary directory", e); + } } void vulnerableFileCreateTempFileMkdirTainted() { + // GIVEN: File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + + // VULNERABLE VERSION: tempDirChild.mkdir(); + + // TO MAKE SAFE REWRITE TO (v1): + File tempSafe1; + try { + tempSafe1 = Files.createTempDirectory(tempDirChild.toPath(), "random").toFile(); + } catch (IOException e) { + throw new RuntimeException("Failed to create temporary directory", e); + } + + // TO MAKE SAFE REWRITE TO (v2): + File tempSafe2; + try { + tempSafe2 = Files.createTempDirectory("random").toFile(); + } catch (IOException e) { + throw new RuntimeException("Failed to create temporary directory", e); + } } void vulnerableFileCreateTempFileMkdirsTainted() { + // GIVEN: File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child"); + + // VULNERABLE VERSION: tempDirChild.mkdirs(); + + // TO MAKE SAFE REWRITE TO (v1): + File tempSafe1; + try { + tempSafe1 = Files.createTempDirectory(tempDirChild.toPath(), "random").toFile(); + } catch (IOException e) { + throw new RuntimeException("Failed to create temporary directory", e); + } + + // TO MAKE SAFE REWRITE TO (v2): + File tempSafe2; + try { + tempSafe2 = Files.createTempDirectory("random").toFile(); + } catch (IOException e) { + throw new RuntimeException("Failed to create temporary directory", e); + } } void vulnerableFileCreateTempFilesWrite1() throws IOException { + // VULNERABLE VERSION: File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); Files.write(tempDirChild.toPath(), Arrays.asList("secret"), StandardCharsets.UTF_8, StandardOpenOption.CREATE); + + // TO MAKE SAFE REWRITE TO (v1): + // Use this version if you care that the file has the exact path of `[java.io.tmpdir]/child.txt` + try { + Path tempSafe = Paths.get(System.getProperty("java.io.tmpdir"), "child.txt"); + Files.createFile(tempSafe, PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); + Files.write(tempSafe, Arrays.asList("secret")); + } catch (IOException e) { + throw new RuntimeException("Failed to write temporary file", e); + } + + // TO MAKE SAFE REWRITE TO (v2): + // Use this version if you don't care that the file has an exact path. This will write to a file of the name `[java.io.tmpdir]/random[random string]child.txt` + try { + Path tempSafe = Files.createTempFile("random", "child.txt"); + Files.write(tempSafe, Arrays.asList("secret"), StandardCharsets.UTF_8, StandardOpenOption.CREATE); + } catch (IOException e) { + throw new RuntimeException("Failed to write temporary file", e); + } } - + void vulnerableFileCreateTempFilesWrite2() throws IOException { - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); + // GIVEN: String secret = "secret"; byte[] byteArrray = secret.getBytes(); + + // VULNERABLE VERSION: + File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child.txt"); Files.write(tempDirChild.toPath(), byteArrray, StandardOpenOption.CREATE); + + // TO MAKE SAFE REWRITE TO (v1): + // Use this version if you care that the file has the exact path of `[java.io.tmpdir]/child.txt` + Path tempSafe1 = Paths.get(System.getProperty("java.io.tmpdir"), "child.txt"); + Files.createFile(tempSafe1, PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); + Files.write(tempSafe1, byteArrray); + + // TO MAKE SAFE REWRITE TO (v2): + // Use this version if you don't care that the file has an exact path. This will write to a file of the name `[java.io.tmpdir]/random[random string]child.txt` + Path tempSafe2 = Files.createTempFile("random", "child.txt"); + Files.write(tempSafe2, byteArrray); } void vulnerableFileCreateTempFilesNewBufferedWriter() throws IOException { - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-buffered-writer.txt"); - Files.newBufferedWriter(tempDirChild.toPath()); + // GIVEN: + Path tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-buffered-writer.txt").toPath(); + + // VULNERABLE VERSION: + Files.newBufferedWriter(tempDirChild); + + // TO MAKE SAFE REWRITE TO: + Files.createFile(tempDirChild, PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); + Files.newBufferedWriter(tempDirChild); } void vulnerableFileCreateTempFilesNewOutputStream() throws IOException { - File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-output-stream.txt"); - Files.newOutputStream(tempDirChild.toPath()).close(); + // GIVEN: + Path tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-output-stream.txt").toPath(); + + // VULNERABLE VERSION: + Files.newOutputStream(tempDirChild).close(); + + // TO MAKE SAFE REWRITE TO: + Files.createFile(tempDirChild, PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); + Files.newOutputStream(tempDirChild).close(); } void vulnerableFileCreateTempFilesCreateFile() throws IOException { + // GIVEN: File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + + // VULNERABLE VERSION: Files.createFile(tempDirChild.toPath()); + + // TO MAKE SAFE REWRITE TO: + Files.createFile(tempDirChild.toPath(), PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); } void safeFileCreateTempFilesCreateFile() throws IOException { - // Clear permissions intentions by setting the 'OWNER_READ' and 'OWNER_WRITE' permissions. + // Clear permissions intentions by setting the 'OWNER_READ' and 'OWNER_WRITE' + // permissions. File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); Files.createFile( - tempDirChild.toPath(), - PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)) - ); + tempDirChild.toPath(), + PosixFilePermissions + .asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); } void vulnerableFileCreateDirectory() throws IOException { + // GIVEN: File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directory"); + + // VULNERABLE VERSION: Files.createDirectory(tempDirChild.toPath()); // Creates with permissions 'drwxr-xr-x' + + // TO MAKE SAFE REWRITE TO: + Files.createDirectory(tempDirChild.toPath(), PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); } void vulnerableFileCreateDirectories() throws IOException { + // GIVEN: File tempDirChild = new File(System.getProperty("java.io.tmpdir"), "/child-create-directories/child"); + + // VULNERABLE VERSION: Files.createDirectories(tempDirChild.toPath()); // Creates with permissions 'drwxr-xr-x' + + // TO MAKE SAFE REWRITE TO: + Files.createDirectories(tempDirChild.toPath(), PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); } } From 0268dd9f0ab5f0fe9ade5fdbbf7ae5f4c6714812 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 1 Feb 2022 16:45:33 +0000 Subject: [PATCH 25/39] Add file creation sanitizer --- ...ocalInformationDisclosureFromMethodCall.ql | 2 +- ...InformationDisclosureFromSystemProperty.ql | 33 ++- ...formationDisclosureFromMethodCall.expected | 6 +- ...ationDisclosureFromSystemProperty.expected | 215 +++++++++--------- 4 files changed, 140 insertions(+), 116 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql index 43812530d44d..1b291ee7d3f2 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql @@ -34,7 +34,7 @@ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCre this.getNumArgument() = 2 or // The default temporary directory is used when the last argument of `File.createTempFile(string, string, File)` is `null` - getArgument(2) instanceof NullLiteral + DataFlow::localExprFlow(any(NullLiteral n), getArgument(2)) ) } diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql index 267ae0de4a3c..c895ff9d6adc 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql @@ -16,8 +16,8 @@ import DataFlow::PathGraph private class MethodFileSystemFileCreation extends Method { MethodFileSystemFileCreation() { - getDeclaringType() instanceof TypeFile and - hasName(["mkdir", "mkdirs", "createNewFile"]) + this.getDeclaringType() instanceof TypeFile and + this.hasName(["mkdir", "mkdirs", "createNewFile"]) } } @@ -58,7 +58,26 @@ private class FilesVulnerableCreationMethodAccess extends MethodAccess { m.hasName(["write", "newBufferedWriter", "newOutputStream"]) or m.hasName(["createFile", "createDirectory", "createDirectories"]) and - getNumArgument() = 1 + this.getNumArgument() = 1 + or + m.hasName("newByteChannel") and + this.getNumArgument() = 2 + ) + } +} + +/** + * A call to a `File` method that create files/directories with a specific set of permissions explicitly set. + * We can safely assume that any calls to these methods with explicit `PosixFilePermissions.asFileAttribute` contains a certain level of intentionality behind it. + */ +private class FilesSanitiznignCreationMethodAccess extends MethodAccess { + FilesSanitiznignCreationMethodAccess() { + exists(Method m | + m = this.getMethod() and + m.getDeclaringType().hasQualifiedName("java.nio.file", "Files") + | + m.hasName(["createFile", "createDirectory", "createDirectories"]) and + this.getNumArgument() = 2 ) } } @@ -92,10 +111,16 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf } override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink } + + override predicate isSanitizer(DataFlow::Node sanitizer) { + exists(FilesSanitiznignCreationMethodAccess sanitisingMethodAccess | + sanitizer.asExpr() = sanitisingMethodAccess.getArgument(0) + ) + } } from DataFlow::PathNode source, DataFlow::PathNode sink, TempDirSystemGetPropertyToCreateConfig conf where conf.hasFlowPath(source, sink) -select source.getNode(), source, sink, +select sink.getNode(), source, sink, "Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users.", source.getNode(), "system temp directory" diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected index d58eb1544168..35f5487ad8c0 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected @@ -1,3 +1,3 @@ -| Test.java:15:21:15:57 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | -| Test.java:19:21:19:63 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | -| Test.java:49:24:49:65 | createTempDir(...) | Local information disclosure vulnerability due to use of directory readable by other local users. | +| Test.java:18:25:18:61 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | +| Test.java:26:25:26:67 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | +| Test.java:95:24:95:65 | createTempDir(...) | Local information disclosure vulnerability due to use of directory readable by other local users. | diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected index dc3f39a8d714..aa4bc32d8d90 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected @@ -6,119 +6,118 @@ edges | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | | Files.java:14:28:14:64 | new File(...) : File | Files.java:15:17:15:23 | tempDir | | Files.java:14:37:14:43 | baseDir : File | Files.java:14:28:14:64 | new File(...) : File | -| Test.java:23:24:23:69 | new File(...) : File | Test.java:24:59:24:65 | tempDir | -| Test.java:23:33:23:68 | getProperty(...) : String | Test.java:23:24:23:69 | new File(...) : File | -| Test.java:23:33:23:68 | getProperty(...) : String | Test.java:24:59:24:65 | tempDir | -| Test.java:28:29:28:94 | new File(...) : File | Test.java:29:59:29:70 | tempDirChild | -| Test.java:28:38:28:83 | new File(...) : File | Test.java:28:29:28:94 | new File(...) : File | -| Test.java:28:38:28:83 | new File(...) : File | Test.java:29:59:29:70 | tempDirChild | -| Test.java:28:47:28:82 | getProperty(...) : String | Test.java:28:38:28:83 | new File(...) : File | -| Test.java:28:47:28:82 | getProperty(...) : String | Test.java:29:59:29:70 | tempDirChild | -| Test.java:33:24:33:69 | new File(...) : File | Test.java:34:59:34:65 | tempDir | -| Test.java:33:33:33:68 | getProperty(...) : String | Test.java:33:24:33:69 | new File(...) : File | -| Test.java:33:33:33:68 | getProperty(...) : String | Test.java:34:59:34:65 | tempDir | -| Test.java:38:24:38:69 | new File(...) : File | Test.java:39:59:39:65 | tempDir | -| Test.java:38:33:38:68 | getProperty(...) : String | Test.java:38:24:38:69 | new File(...) : File | -| Test.java:38:33:38:68 | getProperty(...) : String | Test.java:39:59:39:65 | tempDir | -| Test.java:53:29:53:84 | new File(...) : File | Test.java:54:9:54:20 | tempDirChild | -| Test.java:53:38:53:73 | getProperty(...) : String | Test.java:53:29:53:84 | new File(...) : File | -| Test.java:53:38:53:73 | getProperty(...) : String | Test.java:54:9:54:20 | tempDirChild | -| Test.java:58:29:58:84 | new File(...) : File | Test.java:59:9:59:20 | tempDirChild | -| Test.java:58:38:58:73 | getProperty(...) : String | Test.java:58:29:58:84 | new File(...) : File | -| Test.java:58:38:58:73 | getProperty(...) : String | Test.java:59:9:59:20 | tempDirChild | -| Test.java:63:29:63:88 | new File(...) : File | Test.java:64:21:64:32 | tempDirChild : File | -| Test.java:63:38:63:73 | getProperty(...) : String | Test.java:63:29:63:88 | new File(...) : File | -| Test.java:63:38:63:73 | getProperty(...) : String | Test.java:64:21:64:32 | tempDirChild : File | -| Test.java:64:21:64:32 | tempDirChild : File | Test.java:64:21:64:41 | toPath(...) | -| Test.java:68:29:68:88 | new File(...) : File | Test.java:71:21:71:32 | tempDirChild : File | -| Test.java:68:38:68:73 | getProperty(...) : String | Test.java:68:29:68:88 | new File(...) : File | -| Test.java:68:38:68:73 | getProperty(...) : String | Test.java:71:21:71:32 | tempDirChild : File | -| Test.java:71:21:71:32 | tempDirChild : File | Test.java:71:21:71:41 | toPath(...) | -| Test.java:75:29:75:104 | new File(...) : File | Test.java:76:33:76:44 | tempDirChild : File | -| Test.java:75:38:75:73 | getProperty(...) : String | Test.java:75:29:75:104 | new File(...) : File | -| Test.java:75:38:75:73 | getProperty(...) : String | Test.java:76:33:76:44 | tempDirChild : File | -| Test.java:76:33:76:44 | tempDirChild : File | Test.java:76:33:76:53 | toPath(...) | -| Test.java:80:29:80:102 | new File(...) : File | Test.java:81:31:81:42 | tempDirChild : File | -| Test.java:80:38:80:73 | getProperty(...) : String | Test.java:80:29:80:102 | new File(...) : File | -| Test.java:80:38:80:73 | getProperty(...) : String | Test.java:81:31:81:42 | tempDirChild : File | -| Test.java:81:31:81:42 | tempDirChild : File | Test.java:81:31:81:51 | toPath(...) | -| Test.java:85:29:85:100 | new File(...) : File | Test.java:86:26:86:37 | tempDirChild : File | -| Test.java:85:38:85:73 | getProperty(...) : String | Test.java:85:29:85:100 | new File(...) : File | -| Test.java:85:38:85:73 | getProperty(...) : String | Test.java:86:26:86:37 | tempDirChild : File | -| Test.java:86:26:86:37 | tempDirChild : File | Test.java:86:26:86:46 | toPath(...) | -| Test.java:99:29:99:101 | new File(...) : File | Test.java:100:31:100:42 | tempDirChild : File | -| Test.java:99:38:99:73 | getProperty(...) : String | Test.java:99:29:99:101 | new File(...) : File | -| Test.java:99:38:99:73 | getProperty(...) : String | Test.java:100:31:100:42 | tempDirChild : File | -| Test.java:100:31:100:42 | tempDirChild : File | Test.java:100:31:100:51 | toPath(...) | -| Test.java:104:29:104:109 | new File(...) : File | Test.java:105:33:105:44 | tempDirChild : File | -| Test.java:104:38:104:73 | getProperty(...) : String | Test.java:104:29:104:109 | new File(...) : File | -| Test.java:104:38:104:73 | getProperty(...) : String | Test.java:105:33:105:44 | tempDirChild : File | -| Test.java:105:33:105:44 | tempDirChild : File | Test.java:105:33:105:53 | toPath(...) | +| Test.java:34:24:34:69 | new File(...) : File | Test.java:37:63:37:69 | tempDir | +| Test.java:34:33:34:68 | getProperty(...) : String | Test.java:34:24:34:69 | new File(...) : File | +| Test.java:34:33:34:68 | getProperty(...) : String | Test.java:37:63:37:69 | tempDir | +| Test.java:48:29:48:94 | new File(...) : File | Test.java:51:63:51:74 | tempDirChild | +| Test.java:48:38:48:83 | new File(...) : File | Test.java:48:29:48:94 | new File(...) : File | +| Test.java:48:38:48:83 | new File(...) : File | Test.java:51:63:51:74 | tempDirChild | +| Test.java:48:47:48:82 | getProperty(...) : String | Test.java:48:38:48:83 | new File(...) : File | +| Test.java:48:47:48:82 | getProperty(...) : String | Test.java:51:63:51:74 | tempDirChild | +| Test.java:59:24:59:69 | new File(...) : File | Test.java:62:63:62:69 | tempDir | +| Test.java:59:33:59:68 | getProperty(...) : String | Test.java:59:24:59:69 | new File(...) : File | +| Test.java:59:33:59:68 | getProperty(...) : String | Test.java:62:63:62:69 | tempDir | +| Test.java:73:24:73:69 | new File(...) : File | Test.java:76:63:76:69 | tempDir | +| Test.java:73:33:73:68 | getProperty(...) : String | Test.java:73:24:73:69 | new File(...) : File | +| Test.java:73:33:73:68 | getProperty(...) : String | Test.java:76:63:76:69 | tempDir | +| Test.java:108:29:108:84 | new File(...) : File | Test.java:111:9:111:20 | tempDirChild | +| Test.java:108:38:108:73 | getProperty(...) : String | Test.java:108:29:108:84 | new File(...) : File | +| Test.java:108:38:108:73 | getProperty(...) : String | Test.java:111:9:111:20 | tempDirChild | +| Test.java:132:29:132:84 | new File(...) : File | Test.java:135:9:135:20 | tempDirChild | +| Test.java:132:38:132:73 | getProperty(...) : String | Test.java:132:29:132:84 | new File(...) : File | +| Test.java:132:38:132:73 | getProperty(...) : String | Test.java:135:9:135:20 | tempDirChild | +| Test.java:156:29:156:88 | new File(...) : File | Test.java:157:21:157:32 | tempDirChild : File | +| Test.java:156:38:156:73 | getProperty(...) : String | Test.java:156:29:156:88 | new File(...) : File | +| Test.java:156:38:156:73 | getProperty(...) : String | Test.java:157:21:157:32 | tempDirChild : File | +| Test.java:157:21:157:32 | tempDirChild : File | Test.java:157:21:157:41 | toPath(...) | +| Test.java:185:29:185:88 | new File(...) : File | Test.java:186:21:186:32 | tempDirChild : File | +| Test.java:185:38:185:73 | getProperty(...) : String | Test.java:185:29:185:88 | new File(...) : File | +| Test.java:185:38:185:73 | getProperty(...) : String | Test.java:186:21:186:32 | tempDirChild : File | +| Test.java:186:21:186:32 | tempDirChild : File | Test.java:186:21:186:41 | toPath(...) | +| Test.java:202:29:202:104 | new File(...) : File | Test.java:202:29:202:113 | toPath(...) : Path | +| Test.java:202:29:202:113 | toPath(...) : Path | Test.java:205:33:205:44 | tempDirChild | +| Test.java:202:38:202:73 | getProperty(...) : String | Test.java:202:29:202:104 | new File(...) : File | +| Test.java:214:29:214:102 | new File(...) : File | Test.java:214:29:214:111 | toPath(...) : Path | +| Test.java:214:29:214:111 | toPath(...) : Path | Test.java:217:31:217:42 | tempDirChild | +| Test.java:214:38:214:73 | getProperty(...) : String | Test.java:214:29:214:102 | new File(...) : File | +| Test.java:226:29:226:100 | new File(...) : File | Test.java:229:26:229:37 | tempDirChild : File | +| Test.java:226:38:226:73 | getProperty(...) : String | Test.java:226:29:226:100 | new File(...) : File | +| Test.java:226:38:226:73 | getProperty(...) : String | Test.java:229:26:229:37 | tempDirChild : File | +| Test.java:229:26:229:37 | tempDirChild : File | Test.java:229:26:229:46 | toPath(...) | +| Test.java:247:29:247:101 | new File(...) : File | Test.java:250:31:250:42 | tempDirChild : File | +| Test.java:247:38:247:73 | getProperty(...) : String | Test.java:247:29:247:101 | new File(...) : File | +| Test.java:247:38:247:73 | getProperty(...) : String | Test.java:250:31:250:42 | tempDirChild : File | +| Test.java:250:31:250:42 | tempDirChild : File | Test.java:250:31:250:51 | toPath(...) | +| Test.java:258:29:258:109 | new File(...) : File | Test.java:261:33:261:44 | tempDirChild : File | +| Test.java:258:38:258:73 | getProperty(...) : String | Test.java:258:29:258:109 | new File(...) : File | +| Test.java:258:38:258:73 | getProperty(...) : String | Test.java:261:33:261:44 | tempDirChild : File | +| Test.java:261:33:261:44 | tempDirChild : File | Test.java:261:33:261:53 | toPath(...) | nodes | Files.java:10:24:10:69 | new File(...) : File | semmle.label | new File(...) : File | | Files.java:10:33:10:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Files.java:14:28:14:64 | new File(...) : File | semmle.label | new File(...) : File | | Files.java:14:37:14:43 | baseDir : File | semmle.label | baseDir : File | | Files.java:15:17:15:23 | tempDir | semmle.label | tempDir | -| Test.java:23:24:23:69 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:23:33:23:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:24:59:24:65 | tempDir | semmle.label | tempDir | -| Test.java:28:29:28:94 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:28:38:28:83 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:28:47:28:82 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:29:59:29:70 | tempDirChild | semmle.label | tempDirChild | -| Test.java:33:24:33:69 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:33:33:33:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:34:59:34:65 | tempDir | semmle.label | tempDir | -| Test.java:38:24:38:69 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:38:33:38:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:39:59:39:65 | tempDir | semmle.label | tempDir | -| Test.java:53:29:53:84 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:53:38:53:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:54:9:54:20 | tempDirChild | semmle.label | tempDirChild | -| Test.java:58:29:58:84 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:58:38:58:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:59:9:59:20 | tempDirChild | semmle.label | tempDirChild | -| Test.java:63:29:63:88 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:63:38:63:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:64:21:64:32 | tempDirChild : File | semmle.label | tempDirChild : File | -| Test.java:64:21:64:41 | toPath(...) | semmle.label | toPath(...) | -| Test.java:68:29:68:88 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:68:38:68:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:71:21:71:32 | tempDirChild : File | semmle.label | tempDirChild : File | -| Test.java:71:21:71:41 | toPath(...) | semmle.label | toPath(...) | -| Test.java:75:29:75:104 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:75:38:75:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:76:33:76:44 | tempDirChild : File | semmle.label | tempDirChild : File | -| Test.java:76:33:76:53 | toPath(...) | semmle.label | toPath(...) | -| Test.java:80:29:80:102 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:80:38:80:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:81:31:81:42 | tempDirChild : File | semmle.label | tempDirChild : File | -| Test.java:81:31:81:51 | toPath(...) | semmle.label | toPath(...) | -| Test.java:85:29:85:100 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:85:38:85:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:86:26:86:37 | tempDirChild : File | semmle.label | tempDirChild : File | -| Test.java:86:26:86:46 | toPath(...) | semmle.label | toPath(...) | -| Test.java:99:29:99:101 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:99:38:99:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:100:31:100:42 | tempDirChild : File | semmle.label | tempDirChild : File | -| Test.java:100:31:100:51 | toPath(...) | semmle.label | toPath(...) | -| Test.java:104:29:104:109 | new File(...) : File | semmle.label | new File(...) : File | -| Test.java:104:38:104:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | -| Test.java:105:33:105:44 | tempDirChild : File | semmle.label | tempDirChild : File | -| Test.java:105:33:105:53 | toPath(...) | semmle.label | toPath(...) | +| Test.java:34:24:34:69 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:34:33:34:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:37:63:37:69 | tempDir | semmle.label | tempDir | +| Test.java:48:29:48:94 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:48:38:48:83 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:48:47:48:82 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:51:63:51:74 | tempDirChild | semmle.label | tempDirChild | +| Test.java:59:24:59:69 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:59:33:59:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:62:63:62:69 | tempDir | semmle.label | tempDir | +| Test.java:73:24:73:69 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:73:33:73:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:76:63:76:69 | tempDir | semmle.label | tempDir | +| Test.java:108:29:108:84 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:108:38:108:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:111:9:111:20 | tempDirChild | semmle.label | tempDirChild | +| Test.java:132:29:132:84 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:132:38:132:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:135:9:135:20 | tempDirChild | semmle.label | tempDirChild | +| Test.java:156:29:156:88 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:156:38:156:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:157:21:157:32 | tempDirChild : File | semmle.label | tempDirChild : File | +| Test.java:157:21:157:41 | toPath(...) | semmle.label | toPath(...) | +| Test.java:185:29:185:88 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:185:38:185:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:186:21:186:32 | tempDirChild : File | semmle.label | tempDirChild : File | +| Test.java:186:21:186:41 | toPath(...) | semmle.label | toPath(...) | +| Test.java:202:29:202:104 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:202:29:202:113 | toPath(...) : Path | semmle.label | toPath(...) : Path | +| Test.java:202:38:202:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:205:33:205:44 | tempDirChild | semmle.label | tempDirChild | +| Test.java:214:29:214:102 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:214:29:214:111 | toPath(...) : Path | semmle.label | toPath(...) : Path | +| Test.java:214:38:214:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:217:31:217:42 | tempDirChild | semmle.label | tempDirChild | +| Test.java:226:29:226:100 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:226:38:226:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:229:26:229:37 | tempDirChild : File | semmle.label | tempDirChild : File | +| Test.java:229:26:229:46 | toPath(...) | semmle.label | toPath(...) | +| Test.java:247:29:247:101 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:247:38:247:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:250:31:250:42 | tempDirChild : File | semmle.label | tempDirChild : File | +| Test.java:250:31:250:51 | toPath(...) | semmle.label | toPath(...) | +| Test.java:258:29:258:109 | new File(...) : File | semmle.label | new File(...) : File | +| Test.java:258:38:258:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | +| Test.java:261:33:261:44 | tempDirChild : File | semmle.label | tempDirChild : File | +| Test.java:261:33:261:53 | toPath(...) | semmle.label | toPath(...) | +subpaths #select | Files.java:10:33:10:68 | getProperty(...) | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Files.java:10:33:10:68 | getProperty(...) | system temp directory | -| Test.java:23:33:23:68 | getProperty(...) | Test.java:23:33:23:68 | getProperty(...) : String | Test.java:24:59:24:65 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:23:33:23:68 | getProperty(...) | system temp directory | -| Test.java:28:47:28:82 | getProperty(...) | Test.java:28:47:28:82 | getProperty(...) : String | Test.java:29:59:29:70 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:28:47:28:82 | getProperty(...) | system temp directory | -| Test.java:33:33:33:68 | getProperty(...) | Test.java:33:33:33:68 | getProperty(...) : String | Test.java:34:59:34:65 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:33:33:33:68 | getProperty(...) | system temp directory | -| Test.java:38:33:38:68 | getProperty(...) | Test.java:38:33:38:68 | getProperty(...) : String | Test.java:39:59:39:65 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:38:33:38:68 | getProperty(...) | system temp directory | -| Test.java:53:38:53:73 | getProperty(...) | Test.java:53:38:53:73 | getProperty(...) : String | Test.java:54:9:54:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:53:38:53:73 | getProperty(...) | system temp directory | -| Test.java:58:38:58:73 | getProperty(...) | Test.java:58:38:58:73 | getProperty(...) : String | Test.java:59:9:59:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:58:38:58:73 | getProperty(...) | system temp directory | -| Test.java:63:38:63:73 | getProperty(...) | Test.java:63:38:63:73 | getProperty(...) : String | Test.java:64:21:64:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:63:38:63:73 | getProperty(...) | system temp directory | -| Test.java:68:38:68:73 | getProperty(...) | Test.java:68:38:68:73 | getProperty(...) : String | Test.java:71:21:71:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:68:38:68:73 | getProperty(...) | system temp directory | -| Test.java:75:38:75:73 | getProperty(...) | Test.java:75:38:75:73 | getProperty(...) : String | Test.java:76:33:76:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:75:38:75:73 | getProperty(...) | system temp directory | -| Test.java:80:38:80:73 | getProperty(...) | Test.java:80:38:80:73 | getProperty(...) : String | Test.java:81:31:81:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:80:38:80:73 | getProperty(...) | system temp directory | -| Test.java:85:38:85:73 | getProperty(...) | Test.java:85:38:85:73 | getProperty(...) : String | Test.java:86:26:86:46 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:85:38:85:73 | getProperty(...) | system temp directory | -| Test.java:99:38:99:73 | getProperty(...) | Test.java:99:38:99:73 | getProperty(...) : String | Test.java:100:31:100:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:99:38:99:73 | getProperty(...) | system temp directory | -| Test.java:104:38:104:73 | getProperty(...) | Test.java:104:38:104:73 | getProperty(...) : String | Test.java:105:33:105:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:104:38:104:73 | getProperty(...) | system temp directory | +| Test.java:34:33:34:68 | getProperty(...) | Test.java:34:33:34:68 | getProperty(...) : String | Test.java:37:63:37:69 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:34:33:34:68 | getProperty(...) | system temp directory | +| Test.java:48:47:48:82 | getProperty(...) | Test.java:48:47:48:82 | getProperty(...) : String | Test.java:51:63:51:74 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:48:47:48:82 | getProperty(...) | system temp directory | +| Test.java:59:33:59:68 | getProperty(...) | Test.java:59:33:59:68 | getProperty(...) : String | Test.java:62:63:62:69 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:59:33:59:68 | getProperty(...) | system temp directory | +| Test.java:73:33:73:68 | getProperty(...) | Test.java:73:33:73:68 | getProperty(...) : String | Test.java:76:63:76:69 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:73:33:73:68 | getProperty(...) | system temp directory | +| Test.java:108:38:108:73 | getProperty(...) | Test.java:108:38:108:73 | getProperty(...) : String | Test.java:111:9:111:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:108:38:108:73 | getProperty(...) | system temp directory | +| Test.java:132:38:132:73 | getProperty(...) | Test.java:132:38:132:73 | getProperty(...) : String | Test.java:135:9:135:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:132:38:132:73 | getProperty(...) | system temp directory | +| Test.java:156:38:156:73 | getProperty(...) | Test.java:156:38:156:73 | getProperty(...) : String | Test.java:157:21:157:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:156:38:156:73 | getProperty(...) | system temp directory | +| Test.java:185:38:185:73 | getProperty(...) | Test.java:185:38:185:73 | getProperty(...) : String | Test.java:186:21:186:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:185:38:185:73 | getProperty(...) | system temp directory | +| Test.java:202:38:202:73 | getProperty(...) | Test.java:202:38:202:73 | getProperty(...) : String | Test.java:205:33:205:44 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:202:38:202:73 | getProperty(...) | system temp directory | +| Test.java:214:38:214:73 | getProperty(...) | Test.java:214:38:214:73 | getProperty(...) : String | Test.java:217:31:217:42 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:214:38:214:73 | getProperty(...) | system temp directory | +| Test.java:226:38:226:73 | getProperty(...) | Test.java:226:38:226:73 | getProperty(...) : String | Test.java:229:26:229:46 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:226:38:226:73 | getProperty(...) | system temp directory | +| Test.java:247:38:247:73 | getProperty(...) | Test.java:247:38:247:73 | getProperty(...) : String | Test.java:250:31:250:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:247:38:247:73 | getProperty(...) | system temp directory | +| Test.java:258:38:258:73 | getProperty(...) | Test.java:258:38:258:73 | getProperty(...) : String | Test.java:261:33:261:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:258:38:258:73 | getProperty(...) | system temp directory | From 1f47ea51640a602e4b05351428c683f07d2c282d Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Fri, 4 Feb 2022 17:16:12 -0500 Subject: [PATCH 26/39] Update to new change note format --- ...021-02-25-local-temp-directory-information-disclosure.md | 4 ---- ...4-local-temp-file-or-directory-information-disclosure.md | 6 ++++++ 2 files changed, 6 insertions(+), 4 deletions(-) delete mode 100644 java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md create mode 100644 java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md diff --git a/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md b/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md deleted file mode 100644 index 46654b8f14d8..000000000000 --- a/java/old-change-notes/2021-02-25-local-temp-directory-information-disclosure.md +++ /dev/null @@ -1,4 +0,0 @@ -lgtm,codescanning -* Two new queries, both titled "Temporary directory Local information disclosure" - (`java/local-temp-file-or-directory-information-disclosure-path`, `java/local-temp-file-or-directory-information-disclosure-method`), has been added. - These queries find uses of APIs that leak potentially sensitive information to other local users via the system temporary directory. diff --git a/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md b/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md new file mode 100644 index 000000000000..9206d2b60ea4 --- /dev/null +++ b/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md @@ -0,0 +1,6 @@ +--- +category: newQuery +--- +* Two new querys both titled "Temporary directory Local information disclosure" (`java/local-temp-file-or-directory-information-disclosure-path`, `java/local-temp-file-or-directory-information-disclosure-method`) have been added. + These queries find uses of APIs that leak potentially sensitive information to other local users via the system temporary directory. + This query was originally [submitted as query by @JLLeitschuh](https://github.com/github/codeql/pull/4388). \ No newline at end of file From de38638db61ec4dae3c64913497e9c36ae491fd0 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 7 Feb 2022 12:36:30 +0000 Subject: [PATCH 27/39] Combine CWE-200 queries --- ...> TempDirLocalInformationDisclosure.qhelp} | 6 +- .../TempDirLocalInformationDisclosure.ql | 162 ++++++++++++++++++ ...lInformationDisclosureFromMethodCall.qhelp | 5 - ...ormationDisclosureFromSystemProperty.qhelp | 5 - ...empDirLocalInformationDisclosure.expected} | 12 ++ .../TempDirLocalInformationDisclosure.qlref | 1 + ...lInformationDisclosureFromMethodCall.qlref | 1 - ...ormationDisclosureFromSystemProperty.qlref | 1 - 8 files changed, 178 insertions(+), 15 deletions(-) rename java/ql/src/Security/CWE/CWE-200/{TempDirLocalInformationDisclosure.inc.qhelp => TempDirLocalInformationDisclosure.qhelp} (98%) create mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql delete mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp delete mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp rename java/ql/test/query-tests/security/CWE-200/semmle/tests/{TempDirLocalInformationDisclosureFromSystemProperty.expected => TempDirLocalInformationDisclosure.expected} (86%) create mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.qlref delete mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.qlref delete mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.qlref diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp similarity index 98% rename from java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp rename to java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp index 22a4dd1427b1..f61c9b479919 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.inc.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp @@ -8,8 +8,8 @@ directories that are shared between all users on the system.

              On most unix-like systems, the system temporary directory is shared between local users. -If files/directories are created within the system temporary directory without using -APIs that explicitly set the correct file permissions, local information disclosure +If files/directories are created within the system temporary directory without using +APIs that explicitly set the correct file permissions, local information disclosure can occur.

              Depending upon the particular file contents exposed, this vulnerability can have a @@ -45,4 +45,4 @@ For example: PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePerm

            • OSWAP: Insecure Temporary File.
            • CERT: FIO00-J. Do not operate on files in shared directories
            • - + \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql new file mode 100644 index 000000000000..7464d85a1a4f --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -0,0 +1,162 @@ +/** + * @name Temporary Directory Local information disclosure + * @description Writing information without explicit permissions to a shared temporary directory may disclose it to other users. + * @kind path-problem + * @problem.severity warning + * @precision very-high + * @id java/local-temp-file-or-directory-information-disclosure + * @tags security + * external/cwe/cwe-200 + * external/cwe/cwe-732 + */ + +import java +import TempDirUtils +import DataFlow::PathGraph + +private class MethodFileSystemFileCreation extends Method { + MethodFileSystemFileCreation() { + getDeclaringType() instanceof TypeFile and + hasName(["mkdir", "mkdirs", "createNewFile"]) + } +} + +abstract private class FileCreationSink extends DataFlow::Node { } + +/** + * Sink for tainted `File` having a file or directory creation method called on it. + */ +private class FileFileCreationSink extends FileCreationSink { + FileFileCreationSink() { + exists(MethodAccess ma | + ma.getMethod() instanceof MethodFileSystemFileCreation and + ma.getQualifier() = this.asExpr() + ) + } +} + +/** + * Sink for if tained File/Path having some `Files` method called on it that creates a file or directory. + */ +private class FilesFileCreationSink extends FileCreationSink { + FilesFileCreationSink() { + exists(FilesVulnerableCreationMethodAccess ma | ma.getArgument(0) = this.asExpr()) + } +} + +/** + * Captures all of the vulnerable methods on `Files` that create files/directories without explicitly + * setting the permissions. + */ +private class FilesVulnerableCreationMethodAccess extends MethodAccess { + FilesVulnerableCreationMethodAccess() { + exists(Method m | + m = this.getMethod() and + m.getDeclaringType().hasQualifiedName("java.nio.file", "Files") + | + m.hasName(["write", "newBufferedWriter", "newOutputStream"]) + or + m.hasName(["createFile", "createDirectory", "createDirectories"]) and + getNumArgument() = 1 + ) + } +} + +/** + * A call to `java.io.File::createTempFile` where the the system temp dir sinks to the last argument. + */ +private class FileCreateTempFileSink extends FileCreationSink { + FileCreateTempFileSink() { + exists(MethodAccess ma | + ma.getMethod() instanceof MethodFileCreateTempFile and ma.getArgument(2) = this.asExpr() + ) + } +} + +private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Configuration { + TempDirSystemGetPropertyToCreateConfig() { this = "TempDirSystemGetPropertyToCreateConfig" } + + override predicate isSource(DataFlow::Node source) { + source.asExpr() instanceof MethodAccessSystemGetPropertyTempDirTainted + } + + override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { + isAdditionalFileTaintStep(node1, node2) + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink } +} + +abstract class MethodAccessInsecureFileCreation extends MethodAccess { + /** + * Docstring describing the file system type (ie. file, directory, etc...) returned. + */ + abstract string getFileSystemType(); +} + +/** + * Insecure calls to `java.io.File::createTempFile`. + */ +class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCreation { + MethodAccessInsecureFileCreateTempFile() { + this.getMethod() instanceof MethodFileCreateTempFile and + ( + this.getNumArgument() = 2 + or + // Vulnerablilty exists when the last argument is `null` + getArgument(2) instanceof NullLiteral + ) + } + + override string getFileSystemType() { result = "file" } +} + +class MethodGuavaFilesCreateTempFile extends Method { + MethodGuavaFilesCreateTempFile() { + getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and + hasName("createTempDir") + } +} + +class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureFileCreation { + MethodAccessInsecureGuavaFilesCreateTempFile() { + getMethod() instanceof MethodGuavaFilesCreateTempFile + } + + override string getFileSystemType() { result = "directory" } +} + +/** + * This is a hack: we include use of inherently insecure methods, which don't have any associated + * flow path, in with results describing a path from reading java.io.tmpdir or similar to use + * in a file creation op. + * + * We achieve this by making inherently-insecure method invocations both a source and a sink in + * this configuration, resulting in a zero-length path which is type-compatible with the actual + * path-flow results. + */ +class InsecureMethodPseudoConfiguration extends DataFlow::Configuration { + InsecureMethodPseudoConfiguration() { this = "InsecureMethodPseudoConfiguration " } + + override predicate isSource(DataFlow::Node node) { + node.asExpr() instanceof MethodAccessInsecureFileCreation + } + + override predicate isSink(DataFlow::Node node) { + node.asExpr() instanceof MethodAccessInsecureFileCreation + } +} + +from DataFlow::PathNode source, DataFlow::PathNode sink, string message +where + any(TempDirSystemGetPropertyToCreateConfig conf).hasFlowPath(source, sink) and + message = + "Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users." + or + any(InsecureMethodPseudoConfiguration conf).hasFlowPath(source, sink) and + // Note this message has no "$@" placeholder, so the "system temp directory" template parameter below is not used. + message = + "Local information disclosure vulnerability due to use of " + + source.getNode().asExpr().(MethodAccessInsecureFileCreation).getFileSystemType() + + " readable by other local users." +select source.getNode(), source, sink, message, source.getNode(), "system temp directory" diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp deleted file mode 100644 index 56b902d84d4a..000000000000 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.qhelp +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp deleted file mode 100644 index 56b902d84d4a..000000000000 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.qhelp +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected similarity index 86% rename from java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected rename to java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected index aa4bc32d8d90..505dcf666caa 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected @@ -36,9 +36,11 @@ edges | Test.java:186:21:186:32 | tempDirChild : File | Test.java:186:21:186:41 | toPath(...) | | Test.java:202:29:202:104 | new File(...) : File | Test.java:202:29:202:113 | toPath(...) : Path | | Test.java:202:29:202:113 | toPath(...) : Path | Test.java:205:33:205:44 | tempDirChild | +| Test.java:202:29:202:113 | toPath(...) : Path | Test.java:209:33:209:44 | tempDirChild | | Test.java:202:38:202:73 | getProperty(...) : String | Test.java:202:29:202:104 | new File(...) : File | | Test.java:214:29:214:102 | new File(...) : File | Test.java:214:29:214:111 | toPath(...) : Path | | Test.java:214:29:214:111 | toPath(...) : Path | Test.java:217:31:217:42 | tempDirChild | +| Test.java:214:29:214:111 | toPath(...) : Path | Test.java:221:31:221:42 | tempDirChild | | Test.java:214:38:214:73 | getProperty(...) : String | Test.java:214:29:214:102 | new File(...) : File | | Test.java:226:29:226:100 | new File(...) : File | Test.java:229:26:229:37 | tempDirChild : File | | Test.java:226:38:226:73 | getProperty(...) : String | Test.java:226:29:226:100 | new File(...) : File | @@ -58,6 +60,8 @@ nodes | Files.java:14:28:14:64 | new File(...) : File | semmle.label | new File(...) : File | | Files.java:14:37:14:43 | baseDir : File | semmle.label | baseDir : File | | Files.java:15:17:15:23 | tempDir | semmle.label | tempDir | +| Test.java:18:25:18:61 | createTempFile(...) | semmle.label | createTempFile(...) | +| Test.java:26:25:26:67 | createTempFile(...) | semmle.label | createTempFile(...) | | Test.java:34:24:34:69 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:34:33:34:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:37:63:37:69 | tempDir | semmle.label | tempDir | @@ -71,6 +75,7 @@ nodes | Test.java:73:24:73:69 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:73:33:73:68 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:76:63:76:69 | tempDir | semmle.label | tempDir | +| Test.java:95:24:95:65 | createTempDir(...) | semmle.label | createTempDir(...) | | Test.java:108:29:108:84 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:108:38:108:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:111:9:111:20 | tempDirChild | semmle.label | tempDirChild | @@ -89,10 +94,12 @@ nodes | Test.java:202:29:202:113 | toPath(...) : Path | semmle.label | toPath(...) : Path | | Test.java:202:38:202:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:205:33:205:44 | tempDirChild | semmle.label | tempDirChild | +| Test.java:209:33:209:44 | tempDirChild | semmle.label | tempDirChild | | Test.java:214:29:214:102 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:214:29:214:111 | toPath(...) : Path | semmle.label | toPath(...) : Path | | Test.java:214:38:214:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:217:31:217:42 | tempDirChild | semmle.label | tempDirChild | +| Test.java:221:31:221:42 | tempDirChild | semmle.label | tempDirChild | | Test.java:226:29:226:100 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:226:38:226:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:229:26:229:37 | tempDirChild : File | semmle.label | tempDirChild : File | @@ -108,16 +115,21 @@ nodes subpaths #select | Files.java:10:33:10:68 | getProperty(...) | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Files.java:10:33:10:68 | getProperty(...) | system temp directory | +| Test.java:18:25:18:61 | createTempFile(...) | Test.java:18:25:18:61 | createTempFile(...) | Test.java:18:25:18:61 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | Test.java:18:25:18:61 | createTempFile(...) | system temp directory | +| Test.java:26:25:26:67 | createTempFile(...) | Test.java:26:25:26:67 | createTempFile(...) | Test.java:26:25:26:67 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | Test.java:26:25:26:67 | createTempFile(...) | system temp directory | | Test.java:34:33:34:68 | getProperty(...) | Test.java:34:33:34:68 | getProperty(...) : String | Test.java:37:63:37:69 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:34:33:34:68 | getProperty(...) | system temp directory | | Test.java:48:47:48:82 | getProperty(...) | Test.java:48:47:48:82 | getProperty(...) : String | Test.java:51:63:51:74 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:48:47:48:82 | getProperty(...) | system temp directory | | Test.java:59:33:59:68 | getProperty(...) | Test.java:59:33:59:68 | getProperty(...) : String | Test.java:62:63:62:69 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:59:33:59:68 | getProperty(...) | system temp directory | | Test.java:73:33:73:68 | getProperty(...) | Test.java:73:33:73:68 | getProperty(...) : String | Test.java:76:63:76:69 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:73:33:73:68 | getProperty(...) | system temp directory | +| Test.java:95:24:95:65 | createTempDir(...) | Test.java:95:24:95:65 | createTempDir(...) | Test.java:95:24:95:65 | createTempDir(...) | Local information disclosure vulnerability due to use of directory readable by other local users. | Test.java:95:24:95:65 | createTempDir(...) | system temp directory | | Test.java:108:38:108:73 | getProperty(...) | Test.java:108:38:108:73 | getProperty(...) : String | Test.java:111:9:111:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:108:38:108:73 | getProperty(...) | system temp directory | | Test.java:132:38:132:73 | getProperty(...) | Test.java:132:38:132:73 | getProperty(...) : String | Test.java:135:9:135:20 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:132:38:132:73 | getProperty(...) | system temp directory | | Test.java:156:38:156:73 | getProperty(...) | Test.java:156:38:156:73 | getProperty(...) : String | Test.java:157:21:157:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:156:38:156:73 | getProperty(...) | system temp directory | | Test.java:185:38:185:73 | getProperty(...) | Test.java:185:38:185:73 | getProperty(...) : String | Test.java:186:21:186:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:185:38:185:73 | getProperty(...) | system temp directory | | Test.java:202:38:202:73 | getProperty(...) | Test.java:202:38:202:73 | getProperty(...) : String | Test.java:205:33:205:44 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:202:38:202:73 | getProperty(...) | system temp directory | +| Test.java:202:38:202:73 | getProperty(...) | Test.java:202:38:202:73 | getProperty(...) : String | Test.java:209:33:209:44 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:202:38:202:73 | getProperty(...) | system temp directory | | Test.java:214:38:214:73 | getProperty(...) | Test.java:214:38:214:73 | getProperty(...) : String | Test.java:217:31:217:42 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:214:38:214:73 | getProperty(...) | system temp directory | +| Test.java:214:38:214:73 | getProperty(...) | Test.java:214:38:214:73 | getProperty(...) : String | Test.java:221:31:221:42 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:214:38:214:73 | getProperty(...) | system temp directory | | Test.java:226:38:226:73 | getProperty(...) | Test.java:226:38:226:73 | getProperty(...) : String | Test.java:229:26:229:46 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:226:38:226:73 | getProperty(...) | system temp directory | | Test.java:247:38:247:73 | getProperty(...) | Test.java:247:38:247:73 | getProperty(...) : String | Test.java:250:31:250:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:247:38:247:73 | getProperty(...) | system temp directory | | Test.java:258:38:258:73 | getProperty(...) | Test.java:258:38:258:73 | getProperty(...) : String | Test.java:261:33:261:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:258:38:258:73 | getProperty(...) | system temp directory | diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.qlref new file mode 100644 index 000000000000..e678a2426e75 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.qlref deleted file mode 100644 index 9c785f79c55e..000000000000 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.qlref deleted file mode 100644 index 9c3119da5d2f..000000000000 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromSystemProperty.qlref +++ /dev/null @@ -1 +0,0 @@ -Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql From c4112e6d4ce043ab424205749996ea6bc1448503 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 7 Feb 2022 15:02:13 -0500 Subject: [PATCH 28/39] Post refactor fixiup --- .../TempDirLocalInformationDisclosure.ql | 78 ++++++++--- ...ocalInformationDisclosureFromMethodCall.ql | 68 ---------- ...InformationDisclosureFromSystemProperty.ql | 126 ------------------ ...formationDisclosureFromMethodCall.expected | 3 - 4 files changed, 62 insertions(+), 213 deletions(-) delete mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql delete mode 100644 java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql delete mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index 7464d85a1a4f..b8cc75d37c79 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -16,15 +16,16 @@ import DataFlow::PathGraph private class MethodFileSystemFileCreation extends Method { MethodFileSystemFileCreation() { - getDeclaringType() instanceof TypeFile and - hasName(["mkdir", "mkdirs", "createNewFile"]) + this.getDeclaringType() instanceof TypeFile and + this.hasName(["mkdir", "mkdirs", "createNewFile"]) } } abstract private class FileCreationSink extends DataFlow::Node { } /** - * Sink for tainted `File` having a file or directory creation method called on it. + * The qualifier of a call to one of `File`'s file-creating or directory-creating methods, + * treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. */ private class FileFileCreationSink extends FileCreationSink { FileFileCreationSink() { @@ -36,7 +37,8 @@ private class FileFileCreationSink extends FileCreationSink { } /** - * Sink for if tained File/Path having some `Files` method called on it that creates a file or directory. + * The argument to a call to one of `Files` file-creating or directory-creating methods, + * treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. */ private class FilesFileCreationSink extends FileCreationSink { FilesFileCreationSink() { @@ -45,8 +47,8 @@ private class FilesFileCreationSink extends FileCreationSink { } /** - * Captures all of the vulnerable methods on `Files` that create files/directories without explicitly - * setting the permissions. + * A call to a `Files` method that create files/directories without explicitly + * setting the newly-created file or directory's permissions. */ private class FilesVulnerableCreationMethodAccess extends MethodAccess { FilesVulnerableCreationMethodAccess() { @@ -57,13 +59,34 @@ private class FilesVulnerableCreationMethodAccess extends MethodAccess { m.hasName(["write", "newBufferedWriter", "newOutputStream"]) or m.hasName(["createFile", "createDirectory", "createDirectories"]) and - getNumArgument() = 1 + this.getNumArgument() = 1 + or + m.hasName("newByteChannel") and + this.getNumArgument() = 2 ) } } /** - * A call to `java.io.File::createTempFile` where the the system temp dir sinks to the last argument. + * A call to a `File` method that create files/directories with a specific set of permissions explicitly set. + * We can safely assume that any calls to these methods with explicit `PosixFilePermissions.asFileAttribute` + * contains a certain level of intentionality behind it. + */ +private class FilesSanitiznignCreationMethodAccess extends MethodAccess { + FilesSanitiznignCreationMethodAccess() { + exists(Method m | + m = this.getMethod() and + m.getDeclaringType().hasQualifiedName("java.nio.file", "Files") + | + m.hasName(["createFile", "createDirectory", "createDirectories"]) and + this.getNumArgument() = 2 + ) + } +} + +/** + * The temp directory argument to a call to `java.io.File::createTempFile`, + * treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. */ private class FileCreateTempFileSink extends FileCreationSink { FileCreateTempFileSink() { @@ -80,37 +103,57 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf source.asExpr() instanceof MethodAccessSystemGetPropertyTempDirTainted } + /** + * Find dataflow from the temp directory system property to the `File` constructor. + * Examples: + * - `new File(System.getProperty("java.io.tmpdir"))` + * - `new File(new File(System.getProperty("java.io.tmpdir")), "/child")` + */ override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { isAdditionalFileTaintStep(node1, node2) } override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink } + + override predicate isSanitizer(DataFlow::Node sanitizer) { + exists(FilesSanitiznignCreationMethodAccess sanitisingMethodAccess | + sanitizer.asExpr() = sanitisingMethodAccess.getArgument(0) + ) + } } +// Below this, configuration for tracking single-method calls that are vulnerable. +/** + * A MethodAccess against a method that creates a temporary file or directory in a shared temporary directory. + */ abstract class MethodAccessInsecureFileCreation extends MethodAccess { /** - * Docstring describing the file system type (ie. file, directory, etc...) returned. + * Gets the type of entity created (e.g. `file`, `directory`, ...). */ - abstract string getFileSystemType(); + abstract string getFileSystemEntityType(); } /** - * Insecure calls to `java.io.File::createTempFile`. + * An insecure call to `java.io.File.createTempFile`. */ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCreation { MethodAccessInsecureFileCreateTempFile() { this.getMethod() instanceof MethodFileCreateTempFile and ( + // `File.createTempFile(string, string)` always uses the default temporary directory this.getNumArgument() = 2 or - // Vulnerablilty exists when the last argument is `null` - getArgument(2) instanceof NullLiteral + // The default temporary directory is used when the last argument of `File.createTempFile(string, string, File)` is `null` + DataFlow::localExprFlow(any(NullLiteral n), getArgument(2)) ) } - override string getFileSystemType() { result = "file" } + override string getFileSystemEntityType() { result = "file" } } +/** + * The `com.google.common.io.Files.createTempDir` method. + */ class MethodGuavaFilesCreateTempFile extends Method { MethodGuavaFilesCreateTempFile() { getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and @@ -118,12 +161,15 @@ class MethodGuavaFilesCreateTempFile extends Method { } } +/** + * A call to the `com.google.common.io.Files.createTempDir` method. + */ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureFileCreation { MethodAccessInsecureGuavaFilesCreateTempFile() { getMethod() instanceof MethodGuavaFilesCreateTempFile } - override string getFileSystemType() { result = "directory" } + override string getFileSystemEntityType() { result = "directory" } } /** @@ -157,6 +203,6 @@ where // Note this message has no "$@" placeholder, so the "system temp directory" template parameter below is not used. message = "Local information disclosure vulnerability due to use of " + - source.getNode().asExpr().(MethodAccessInsecureFileCreation).getFileSystemType() + + source.getNode().asExpr().(MethodAccessInsecureFileCreation).getFileSystemEntityType() + " readable by other local users." select source.getNode(), source, sink, message, source.getNode(), "system temp directory" diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql deleted file mode 100644 index 1b291ee7d3f2..000000000000 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromMethodCall.ql +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @name Temporary directory local information disclosure (file creation via inherently insecure method) - * @description Creating a temporary file in the system shared temporary directory, using a method that always creates it world-readable, may disclose its contents to other users. - * @kind problem - * @problem.severity warning - * @precision very-high - * @id java/local-temp-file-or-directory-information-disclosure-insecure-method - * @tags security - * external/cwe/cwe-200 - * external/cwe/cwe-732 - */ - -import java -import TempDirUtils - -/** - * A MethodAccess against a method that creates a temporary file or directory in a shared temporary directory. - */ -abstract class MethodAccessInsecureFileCreation extends MethodAccess { - /** - * Gets the type of entity created (e.g. `file`, `directory`, ...). - */ - abstract string getFileSystemEntityType(); -} - -/** - * An insecure call to `java.io.File.createTempFile`. - */ -class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCreation { - MethodAccessInsecureFileCreateTempFile() { - this.getMethod() instanceof MethodFileCreateTempFile and - ( - // `File.createTempFile(string, string)` always uses the default temporary directory - this.getNumArgument() = 2 - or - // The default temporary directory is used when the last argument of `File.createTempFile(string, string, File)` is `null` - DataFlow::localExprFlow(any(NullLiteral n), getArgument(2)) - ) - } - - override string getFileSystemEntityType() { result = "file" } -} - -/** - * The `com.google.common.io.Files.createTempDir` method. - */ -class MethodGuavaFilesCreateTempFile extends Method { - MethodGuavaFilesCreateTempFile() { - getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and - hasName("createTempDir") - } -} - -/** - * A call to the `com.google.common.io.Files.createTempDir` method. - */ -class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureFileCreation { - MethodAccessInsecureGuavaFilesCreateTempFile() { - getMethod() instanceof MethodGuavaFilesCreateTempFile - } - - override string getFileSystemEntityType() { result = "directory" } -} - -from MethodAccessInsecureFileCreation methodAccess -select methodAccess, - "Local information disclosure vulnerability due to use of " + - methodAccess.getFileSystemEntityType() + " readable by other local users." diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql deleted file mode 100644 index c895ff9d6adc..000000000000 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosureFromSystemProperty.ql +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @name Temporary directory local information disclosure (file creation without explicit mode) - * @description Creating a temporary file in the system shared temporary directory without specifying explicit access rights (mode) may disclose its contents to other users. - * @kind path-problem - * @problem.severity warning - * @precision very-high - * @id java/local-temp-file-or-directory-information-disclosure-missing-mode - * @tags security - * external/cwe/cwe-200 - * external/cwe/cwe-732 - */ - -import java -import TempDirUtils -import DataFlow::PathGraph - -private class MethodFileSystemFileCreation extends Method { - MethodFileSystemFileCreation() { - this.getDeclaringType() instanceof TypeFile and - this.hasName(["mkdir", "mkdirs", "createNewFile"]) - } -} - -abstract private class FileCreationSink extends DataFlow::Node { } - -/** - * The qualifier of a call to one of `File`'s file-creating or directory-creating methods, treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. - */ -private class FileFileCreationSink extends FileCreationSink { - FileFileCreationSink() { - exists(MethodAccess ma | - ma.getMethod() instanceof MethodFileSystemFileCreation and - ma.getQualifier() = this.asExpr() - ) - } -} - -/** - * The argument to - * a call to one of `Files` file-creating or directory-creating methods, treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. - */ -private class FilesFileCreationSink extends FileCreationSink { - FilesFileCreationSink() { - exists(FilesVulnerableCreationMethodAccess ma | ma.getArgument(0) = this.asExpr()) - } -} - -/** - * A call to a `Files` method that create files/directories without explicitly - * setting the newly-created file or directory's permissions. - */ -private class FilesVulnerableCreationMethodAccess extends MethodAccess { - FilesVulnerableCreationMethodAccess() { - exists(Method m | - m = this.getMethod() and - m.getDeclaringType().hasQualifiedName("java.nio.file", "Files") - | - m.hasName(["write", "newBufferedWriter", "newOutputStream"]) - or - m.hasName(["createFile", "createDirectory", "createDirectories"]) and - this.getNumArgument() = 1 - or - m.hasName("newByteChannel") and - this.getNumArgument() = 2 - ) - } -} - -/** - * A call to a `File` method that create files/directories with a specific set of permissions explicitly set. - * We can safely assume that any calls to these methods with explicit `PosixFilePermissions.asFileAttribute` contains a certain level of intentionality behind it. - */ -private class FilesSanitiznignCreationMethodAccess extends MethodAccess { - FilesSanitiznignCreationMethodAccess() { - exists(Method m | - m = this.getMethod() and - m.getDeclaringType().hasQualifiedName("java.nio.file", "Files") - | - m.hasName(["createFile", "createDirectory", "createDirectories"]) and - this.getNumArgument() = 2 - ) - } -} - -/** - * The temp directory argument to a call to `java.io.File::createTempFile`, treated as a sink by `TempDirSystemGetPropertyToCreateConfig`. - */ -private class FileCreateTempFileSink extends FileCreationSink { - FileCreateTempFileSink() { - exists(MethodAccess ma | - ma.getMethod() instanceof MethodFileCreateTempFile and ma.getArgument(2) = this.asExpr() - ) - } -} - -private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Configuration { - TempDirSystemGetPropertyToCreateConfig() { this = "TempDirSystemGetPropertyToCreateConfig" } - - override predicate isSource(DataFlow::Node source) { - source.asExpr() instanceof MethodAccessSystemGetPropertyTempDirTainted - } - - /** - * Find dataflow from the temp directory system property to the `File` constructor. - * Examples: - * - `new File(System.getProperty("java.io.tmpdir"))` - * - `new File(new File(System.getProperty("java.io.tmpdir")), "/child")` - */ - override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - isAdditionalFileTaintStep(node1, node2) - } - - override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink } - - override predicate isSanitizer(DataFlow::Node sanitizer) { - exists(FilesSanitiznignCreationMethodAccess sanitisingMethodAccess | - sanitizer.asExpr() = sanitisingMethodAccess.getArgument(0) - ) - } -} - -from DataFlow::PathNode source, DataFlow::PathNode sink, TempDirSystemGetPropertyToCreateConfig conf -where conf.hasFlowPath(source, sink) -select sink.getNode(), source, sink, - "Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users.", - source.getNode(), "system temp directory" diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected deleted file mode 100644 index 35f5487ad8c0..000000000000 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosureFromMethodCall.expected +++ /dev/null @@ -1,3 +0,0 @@ -| Test.java:18:25:18:61 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | -| Test.java:26:25:26:67 | createTempFile(...) | Local information disclosure vulnerability due to use of file readable by other local users. | -| Test.java:95:24:95:65 | createTempDir(...) | Local information disclosure vulnerability due to use of directory readable by other local users. | From 79654592d92a5d9532b60affb3f41e1df0485383 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 8 Feb 2022 10:23:46 +0000 Subject: [PATCH 29/39] Apply suggestions from code review --- .../TempDirLocalInformationDisclosure.ql | 17 ++++++++++------- ...-file-or-directory-information-disclosure.md | 4 ++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index b8cc75d37c79..29664ed0ae9b 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -72,8 +72,8 @@ private class FilesVulnerableCreationMethodAccess extends MethodAccess { * We can safely assume that any calls to these methods with explicit `PosixFilePermissions.asFileAttribute` * contains a certain level of intentionality behind it. */ -private class FilesSanitiznignCreationMethodAccess extends MethodAccess { - FilesSanitiznignCreationMethodAccess() { +private class FilesSanitizingCreationMethodAccess extends MethodAccess { + FilesSanitizingCreationMethodAccess() { exists(Method m | m = this.getMethod() and m.getDeclaringType().hasQualifiedName("java.nio.file", "Files") @@ -116,15 +116,18 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink } override predicate isSanitizer(DataFlow::Node sanitizer) { - exists(FilesSanitiznignCreationMethodAccess sanitisingMethodAccess | + exists(FilesSanitizingCreationMethodAccess sanitisingMethodAccess | sanitizer.asExpr() = sanitisingMethodAccess.getArgument(0) ) } } -// Below this, configuration for tracking single-method calls that are vulnerable. +// +// Begin configuration for tracking single-method calls that are vulnerable. +// + /** - * A MethodAccess against a method that creates a temporary file or directory in a shared temporary directory. + * A `MethodAccess` against a method that creates a temporary file or directory in a shared temporary directory. */ abstract class MethodAccessInsecureFileCreation extends MethodAccess { /** @@ -174,7 +177,7 @@ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureF /** * This is a hack: we include use of inherently insecure methods, which don't have any associated - * flow path, in with results describing a path from reading java.io.tmpdir or similar to use + * flow path, in with results describing a path from reading `java.io.tmpdir` or similar to use * in a file creation op. * * We achieve this by making inherently-insecure method invocations both a source and a sink in @@ -182,7 +185,7 @@ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureF * path-flow results. */ class InsecureMethodPseudoConfiguration extends DataFlow::Configuration { - InsecureMethodPseudoConfiguration() { this = "InsecureMethodPseudoConfiguration " } + InsecureMethodPseudoConfiguration() { this = "InsecureMethodPseudoConfiguration" } override predicate isSource(DataFlow::Node node) { node.asExpr() instanceof MethodAccessInsecureFileCreation diff --git a/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md b/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md index 9206d2b60ea4..8112470d2b3e 100644 --- a/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md +++ b/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md @@ -1,6 +1,6 @@ --- category: newQuery --- -* Two new querys both titled "Temporary directory Local information disclosure" (`java/local-temp-file-or-directory-information-disclosure-path`, `java/local-temp-file-or-directory-information-disclosure-method`) have been added. - These queries find uses of APIs that leak potentially sensitive information to other local users via the system temporary directory. +* A new query titled "Temporary directory Local information disclosure" (`java/local-temp-file-or-directory-information-disclosure`) has been added. + This query finds uses of APIs that leak potentially sensitive information to other local users via the system temporary directory. This query was originally [submitted as query by @JLLeitschuh](https://github.com/github/codeql/pull/4388). \ No newline at end of file From a6596ea7ce6539809f5b72526abbcbb4b33bbc7e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Tue, 8 Feb 2022 12:01:32 +0000 Subject: [PATCH 30/39] Fix test requirements, formatting --- .../CWE/CWE-200/TempDirLocalInformationDisclosure.ql | 1 - .../semmle/tests/TempDirLocalInformationDisclosure.expected | 6 ------ 2 files changed, 7 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index 29664ed0ae9b..be14d44b5766 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -125,7 +125,6 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf // // Begin configuration for tracking single-method calls that are vulnerable. // - /** * A `MethodAccess` against a method that creates a temporary file or directory in a shared temporary directory. */ diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected index 505dcf666caa..48e09b70f3c3 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected @@ -36,11 +36,9 @@ edges | Test.java:186:21:186:32 | tempDirChild : File | Test.java:186:21:186:41 | toPath(...) | | Test.java:202:29:202:104 | new File(...) : File | Test.java:202:29:202:113 | toPath(...) : Path | | Test.java:202:29:202:113 | toPath(...) : Path | Test.java:205:33:205:44 | tempDirChild | -| Test.java:202:29:202:113 | toPath(...) : Path | Test.java:209:33:209:44 | tempDirChild | | Test.java:202:38:202:73 | getProperty(...) : String | Test.java:202:29:202:104 | new File(...) : File | | Test.java:214:29:214:102 | new File(...) : File | Test.java:214:29:214:111 | toPath(...) : Path | | Test.java:214:29:214:111 | toPath(...) : Path | Test.java:217:31:217:42 | tempDirChild | -| Test.java:214:29:214:111 | toPath(...) : Path | Test.java:221:31:221:42 | tempDirChild | | Test.java:214:38:214:73 | getProperty(...) : String | Test.java:214:29:214:102 | new File(...) : File | | Test.java:226:29:226:100 | new File(...) : File | Test.java:229:26:229:37 | tempDirChild : File | | Test.java:226:38:226:73 | getProperty(...) : String | Test.java:226:29:226:100 | new File(...) : File | @@ -94,12 +92,10 @@ nodes | Test.java:202:29:202:113 | toPath(...) : Path | semmle.label | toPath(...) : Path | | Test.java:202:38:202:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:205:33:205:44 | tempDirChild | semmle.label | tempDirChild | -| Test.java:209:33:209:44 | tempDirChild | semmle.label | tempDirChild | | Test.java:214:29:214:102 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:214:29:214:111 | toPath(...) : Path | semmle.label | toPath(...) : Path | | Test.java:214:38:214:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:217:31:217:42 | tempDirChild | semmle.label | tempDirChild | -| Test.java:221:31:221:42 | tempDirChild | semmle.label | tempDirChild | | Test.java:226:29:226:100 | new File(...) : File | semmle.label | new File(...) : File | | Test.java:226:38:226:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:229:26:229:37 | tempDirChild : File | semmle.label | tempDirChild : File | @@ -127,9 +123,7 @@ subpaths | Test.java:156:38:156:73 | getProperty(...) | Test.java:156:38:156:73 | getProperty(...) : String | Test.java:157:21:157:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:156:38:156:73 | getProperty(...) | system temp directory | | Test.java:185:38:185:73 | getProperty(...) | Test.java:185:38:185:73 | getProperty(...) : String | Test.java:186:21:186:41 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:185:38:185:73 | getProperty(...) | system temp directory | | Test.java:202:38:202:73 | getProperty(...) | Test.java:202:38:202:73 | getProperty(...) : String | Test.java:205:33:205:44 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:202:38:202:73 | getProperty(...) | system temp directory | -| Test.java:202:38:202:73 | getProperty(...) | Test.java:202:38:202:73 | getProperty(...) : String | Test.java:209:33:209:44 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:202:38:202:73 | getProperty(...) | system temp directory | | Test.java:214:38:214:73 | getProperty(...) | Test.java:214:38:214:73 | getProperty(...) : String | Test.java:217:31:217:42 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:214:38:214:73 | getProperty(...) | system temp directory | -| Test.java:214:38:214:73 | getProperty(...) | Test.java:214:38:214:73 | getProperty(...) : String | Test.java:221:31:221:42 | tempDirChild | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:214:38:214:73 | getProperty(...) | system temp directory | | Test.java:226:38:226:73 | getProperty(...) | Test.java:226:38:226:73 | getProperty(...) : String | Test.java:229:26:229:46 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:226:38:226:73 | getProperty(...) | system temp directory | | Test.java:247:38:247:73 | getProperty(...) | Test.java:247:38:247:73 | getProperty(...) : String | Test.java:250:31:250:51 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:247:38:247:73 | getProperty(...) | system temp directory | | Test.java:258:38:258:73 | getProperty(...) | Test.java:258:38:258:73 | getProperty(...) : String | Test.java:261:33:261:53 | toPath(...) | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Test.java:258:38:258:73 | getProperty(...) | system temp directory | From 7f466401762f8ec2884246fe7f5913ff29a9030a Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Tue, 8 Feb 2022 17:57:10 -0500 Subject: [PATCH 31/39] Consider calls to setReadable(false, false) then setReadable(true, true) to be safe --- .../TempDirLocalInformationDisclosure.ql | 23 +++++---- .../src/Security/CWE/CWE-200/TempDirUtils.qll | 51 ++++++++++++++++++- .../security/CWE-200/semmle/tests/Test.java | 6 +++ 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index be14d44b5766..7d0a7ecca3e0 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -197,14 +197,17 @@ class InsecureMethodPseudoConfiguration extends DataFlow::Configuration { from DataFlow::PathNode source, DataFlow::PathNode sink, string message where - any(TempDirSystemGetPropertyToCreateConfig conf).hasFlowPath(source, sink) and - message = - "Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users." - or - any(InsecureMethodPseudoConfiguration conf).hasFlowPath(source, sink) and - // Note this message has no "$@" placeholder, so the "system temp directory" template parameter below is not used. - message = - "Local information disclosure vulnerability due to use of " + - source.getNode().asExpr().(MethodAccessInsecureFileCreation).getFileSystemEntityType() + - " readable by other local users." + ( + any(TempDirSystemGetPropertyToCreateConfig conf).hasFlowPath(source, sink) and + message = + "Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users." + or + any(InsecureMethodPseudoConfiguration conf).hasFlowPath(source, sink) and + // Note this message has no "$@" placeholder, so the "system temp directory" template parameter below is not used. + message = + "Local information disclosure vulnerability due to use of " + + source.getNode().asExpr().(MethodAccessInsecureFileCreation).getFileSystemEntityType() + + " readable by other local users." + ) and + not isPermissionsProtectedTempDirUse(sink.getNode()) select source.getNode(), source, sink, message, source.getNode(), "system temp directory" diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index 0613006f71f9..c6df9549dc65 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -59,8 +59,8 @@ private predicate isFileConstructorArgument(Expr expSource, Expr exprDest) { */ private class TaintFollowingFileMethod extends Method { TaintFollowingFileMethod() { - getDeclaringType() instanceof TypeFile and - hasName(["getAbsoluteFile", "getCanonicalFile"]) + this.getDeclaringType() instanceof TypeFile and + this.hasName(["getAbsoluteFile", "getCanonicalFile"]) } } @@ -80,3 +80,50 @@ predicate isAdditionalFileTaintStep(DataFlow::Node node1, DataFlow::Node node2) isFileConstructorArgument(node1.asExpr(), node2.asExpr()) or isTaintPropagatingFileTransformation(node1.asExpr(), node2.asExpr()) } + +/** + * A method call to `java.io.File::setReadable`. + */ +private class FileSetRedableMethodAccess extends MethodAccess { + FileSetRedableMethodAccess() { + exists(Method m | this.getMethod() = m | + m.getDeclaringType() instanceof TypeFile and + m.hasName("setReadable") + ) + } + + predicate isCallWithArguments(boolean arg1, boolean arg2) { + this.isCallWithArgument(0, arg1) and this.isCallToSecondArgumentWithValue(arg2) + } + + private predicate isCallToSecondArgumentWithValue(boolean value) { + this.getMethod().getNumberOfParameters() = 1 and value = true + or + isCallWithArgument(1, value) + } + + private predicate isCallWithArgument(int index, boolean arg) { + DataFlow::localExprFlow(any(CompileTimeConstantExpr e | e.getBooleanValue() = arg), + this.getArgument(index)) + } +} + +/** + * Hold's if temporary directory's use is protected if there is an explicit call to + * `setReadable(false, false)`, then `setRedabale(true, true)`. + */ +predicate isPermissionsProtectedTempDirUse(DataFlow::Node sink) { + exists(FileSetRedableMethodAccess setReadable1, FileSetRedableMethodAccess setReadable2 | + setReadable1.isCallWithArguments(false, false) and + setReadable2.isCallWithArguments(true, true) + | + exists(DataFlow::Node setReadableNode1, DataFlow::Node setReadableNode2 | + setReadableNode1.asExpr() = setReadable1.getQualifier() and + setReadableNode2.asExpr() = setReadable2.getQualifier() + | + DataFlow::localFlow(sink, setReadableNode1) and // Flow from sink to setReadable(false, false) + DataFlow::localFlow(sink, setReadableNode2) and // Flow from sink to setReadable(true, true) + DataFlow::localFlow(setReadableNode1, setReadableNode2) // Flow from setReadable(false, false) to setReadable(true, true) + ) + ) +} diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java index 44b8210e6584..fc1e9eb09048 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -263,4 +263,10 @@ void vulnerableFileCreateDirectories() throws IOException { // TO MAKE SAFE REWRITE TO: Files.createDirectories(tempDirChild.toPath(), PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); } + + void safeFileCreationWithPermissions() throws IOException { + File tempFile = File.createTempFile("temp", "file.txt"); + tempFile.setReadable(false, false); + tempFile.setReadable(true, true); + } } From 787e3dac31c4d6fcf76354192328e3dee3a04148 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Wed, 9 Feb 2022 10:07:56 -0500 Subject: [PATCH 32/39] Update java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql Co-authored-by: Chris Smowton --- .../Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index 7d0a7ecca3e0..60721dbf7f27 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -3,7 +3,7 @@ * @description Writing information without explicit permissions to a shared temporary directory may disclose it to other users. * @kind path-problem * @problem.severity warning - * @precision very-high + * @precision medium * @id java/local-temp-file-or-directory-information-disclosure * @tags security * external/cwe/cwe-200 From 49a73673b64dd02e1581be5cbf13d5fbfc3ca330 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Wed, 9 Feb 2022 11:01:54 -0500 Subject: [PATCH 33/39] Fix FP from mkdirs call on exact temp directory --- .../TempDirLocalInformationDisclosure.ql | 57 +++++++++++++++++-- .../src/Security/CWE/CWE-200/TempDirUtils.qll | 7 ++- .../security/CWE-200/semmle/tests/Test.java | 10 ++++ 3 files changed, 65 insertions(+), 9 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index 60721dbf7f27..9a3fbfe55fbd 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -13,12 +13,18 @@ import java import TempDirUtils import DataFlow::PathGraph +import semmle.code.java.dataflow.TaintTracking2 -private class MethodFileSystemFileCreation extends Method { - MethodFileSystemFileCreation() { - this.getDeclaringType() instanceof TypeFile and - this.hasName(["mkdir", "mkdirs", "createNewFile"]) - } +abstract private class MethodFileSystemFileCreation extends Method { + MethodFileSystemFileCreation() { this.getDeclaringType() instanceof TypeFile } +} + +private class MethodFileDirectoryCreation extends MethodFileSystemFileCreation { + MethodFileDirectoryCreation() { this.hasName(["mkdir", "mkdirs"]) } +} + +private class MethodFileFileCreation extends MethodFileSystemFileCreation { + MethodFileFileCreation() { this.hasName(["createNewFile"]) } } abstract private class FileCreationSink extends DataFlow::Node { } @@ -113,7 +119,10 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf isAdditionalFileTaintStep(node1, node2) } - override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink } + override predicate isSink(DataFlow::Node sink) { + sink instanceof FileCreationSink and + exists(TempDirSystemGetPropertyDirectlyToMkdirConfig config | not config.hasFlowTo(sink)) + } override predicate isSanitizer(DataFlow::Node sanitizer) { exists(FilesSanitizingCreationMethodAccess sanitisingMethodAccess | @@ -122,6 +131,42 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf } } +/** + * Configuration that tracks calls to to `mkdir` or `mkdirs` that are are directly on the temp directory system property. + * Examples: + * - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdir();` + * - `File tempDir = new File(System.getProperty("java.io.tmpdir")); tempDir.mkdirs();` + * + * These are examples of code that is simply verifying that the temp directory exists. + * As such, this code pattern is filtered out as an explicit vulnerability in + * `TempDirSystemGetPropertyToCreateConfig::isSink`. + */ +private class TempDirSystemGetPropertyDirectlyToMkdirConfig extends TaintTracking2::Configuration { + TempDirSystemGetPropertyDirectlyToMkdirConfig() { + this = "TempDirSystemGetPropertyDirectlyToMkdirConfig" + } + + override predicate isSource(DataFlow::Node node) { + exists( + MethodAccessSystemGetPropertyTempDirTainted propertyGetMethodAccess, DataFlow::Node callSite + | + DataFlow::localFlow(DataFlow::exprNode(propertyGetMethodAccess), callSite) + | + isFileConstructorArgument(callSite.asExpr(), node.asExpr(), 1) + ) + } + + override predicate isSink(DataFlow::Node node) { + exists(MethodAccess ma | ma.getMethod() instanceof MethodFileDirectoryCreation | + ma.getQualifier() = node.asExpr() + ) + } + + override predicate isSanitizer(DataFlow::Node sanitizer) { + isFileConstructorArgument(sanitizer.asExpr(), _, _) + } +} + // // Begin configuration for tracking single-method calls that are vulnerable. // diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index c6df9549dc65..0c2409c04084 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -46,11 +46,12 @@ class MethodFileCreateTempFile extends Method { /** * Holds if `expDest` is some constructor call `new java.io.File(x)` and `expSource` is `x`. */ -private predicate isFileConstructorArgument(Expr expSource, Expr exprDest) { +predicate isFileConstructorArgument(Expr expSource, Expr exprDest, int paramCount) { exists(ConstructorCall construtorCall | construtorCall.getConstructedType() instanceof TypeFile and construtorCall.getArgument(0) = expSource and - construtorCall = exprDest + construtorCall = exprDest and + construtorCall.getConstructor().getNumberOfParameters() = paramCount ) } @@ -77,7 +78,7 @@ private predicate isTaintPropagatingFileTransformation(Expr expSource, Expr expr * For example, `taintedFile.getCanonicalFile()` is itself tainted. */ predicate isAdditionalFileTaintStep(DataFlow::Node node1, DataFlow::Node node2) { - isFileConstructorArgument(node1.asExpr(), node2.asExpr()) or + isFileConstructorArgument(node1.asExpr(), node2.asExpr(), _) or isTaintPropagatingFileTransformation(node1.asExpr(), node2.asExpr()) } diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java index fc1e9eb09048..b5b708692f1b 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/Test.java @@ -269,4 +269,14 @@ void safeFileCreationWithPermissions() throws IOException { tempFile.setReadable(false, false); tempFile.setReadable(true, true); } + + void notVulnerableCreateOnSystemPropertyDir() throws IOException { + File tempDir = new File(System.getProperty("java.io.tmpdir")); + tempDir.mkdir(); + } + + void notVulnerableCreateOnSystemPropertyDirs() throws IOException { + File tempDir = new File(System.getProperty("java.io.tmpdir")); + tempDir.mkdirs(); + } } From bafcce17d43064db7995948c03c24ad4a981ff94 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Wed, 9 Feb 2022 22:14:17 -0500 Subject: [PATCH 34/39] Apply suggestions from code review Co-authored-by: Chris Smowton --- .../Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql | 2 +- java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index 9a3fbfe55fbd..b2649a079625 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -121,7 +121,7 @@ private class TempDirSystemGetPropertyToCreateConfig extends TaintTracking::Conf override predicate isSink(DataFlow::Node sink) { sink instanceof FileCreationSink and - exists(TempDirSystemGetPropertyDirectlyToMkdirConfig config | not config.hasFlowTo(sink)) + not any(TempDirSystemGetPropertyDirectlyToMkdirConfig config).hasFlowTo(sink) } override predicate isSanitizer(DataFlow::Node sanitizer) { diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll index 0c2409c04084..d2a2bcb5a6fb 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUtils.qll @@ -44,7 +44,7 @@ class MethodFileCreateTempFile extends Method { } /** - * Holds if `expDest` is some constructor call `new java.io.File(x)` and `expSource` is `x`. + * Holds if `expDest` is some constructor call `new java.io.File(expSource)`, where the specific `File` constructor being used has `paramCount` parameters. */ predicate isFileConstructorArgument(Expr expSource, Expr exprDest, int paramCount) { exists(ConstructorCall construtorCall | From eee521e6cee2c649ad9f02d12e88c828b75ed901 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Thu, 10 Feb 2022 10:40:40 -0500 Subject: [PATCH 35/39] Fix test failure for TempDirLocalInformationDisclosure --- .../semmle/tests/TempDirLocalInformationDisclosure.expected | 1 + 1 file changed, 1 insertion(+) diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected index 48e09b70f3c3..7c21c3667a3f 100644 --- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected +++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/TempDirLocalInformationDisclosure.expected @@ -108,6 +108,7 @@ nodes | Test.java:258:38:258:73 | getProperty(...) : String | semmle.label | getProperty(...) : String | | Test.java:261:33:261:44 | tempDirChild : File | semmle.label | tempDirChild : File | | Test.java:261:33:261:53 | toPath(...) | semmle.label | toPath(...) | +| Test.java:268:25:268:63 | createTempFile(...) | semmle.label | createTempFile(...) | subpaths #select | Files.java:10:33:10:68 | getProperty(...) | Files.java:10:33:10:68 | getProperty(...) : String | Files.java:15:17:15:23 | tempDir | Local information disclosure vulnerability from $@ due to use of file or directory readable by other local users. | Files.java:10:33:10:68 | getProperty(...) | system temp directory | From 7dee22a1302ae997d8d2ed62bb73c51ce4f1fb09 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 14 Feb 2022 11:00:41 -0500 Subject: [PATCH 36/39] Fix implicit 'this' usage --- .../CWE/CWE-200/TempDirLocalInformationDisclosure.ql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index b2649a079625..c32a139f0f2d 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -24,7 +24,7 @@ private class MethodFileDirectoryCreation extends MethodFileSystemFileCreation { } private class MethodFileFileCreation extends MethodFileSystemFileCreation { - MethodFileFileCreation() { this.hasName(["createNewFile"]) } + MethodFileFileCreation() { this.hasName("createNewFile") } } abstract private class FileCreationSink extends DataFlow::Node { } @@ -191,7 +191,7 @@ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCre this.getNumArgument() = 2 or // The default temporary directory is used when the last argument of `File.createTempFile(string, string, File)` is `null` - DataFlow::localExprFlow(any(NullLiteral n), getArgument(2)) + DataFlow::localExprFlow(any(NullLiteral n), this.getArgument(2)) ) } @@ -203,8 +203,8 @@ class MethodAccessInsecureFileCreateTempFile extends MethodAccessInsecureFileCre */ class MethodGuavaFilesCreateTempFile extends Method { MethodGuavaFilesCreateTempFile() { - getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and - hasName("createTempDir") + this.getDeclaringType().hasQualifiedName("com.google.common.io", "Files") and + this.hasName("createTempDir") } } @@ -213,14 +213,14 @@ class MethodGuavaFilesCreateTempFile extends Method { */ class MethodAccessInsecureGuavaFilesCreateTempFile extends MethodAccessInsecureFileCreation { MethodAccessInsecureGuavaFilesCreateTempFile() { - getMethod() instanceof MethodGuavaFilesCreateTempFile + this.getMethod() instanceof MethodGuavaFilesCreateTempFile } override string getFileSystemEntityType() { result = "directory" } } /** - * This is a hack: we include use of inherently insecure methods, which don't have any associated + * A hack: we include use of inherently insecure methods, which don't have any associated * flow path, in with results describing a path from reading `java.io.tmpdir` or similar to use * in a file creation op. * From bb580ddbab7da0a1bca46d4a2bbb1e3a6c6b79f6 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 14 Feb 2022 11:02:05 -0500 Subject: [PATCH 37/39] Apply suggestions from code review Co-authored-by: Felicity Chapman --- .../CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp | 1 + .../Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp index f61c9b479919..883186f46ea8 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp @@ -22,6 +22,7 @@ can occur.

            • java.nio.file.Files.createTempDirectory
            • java.nio.file.Files.createTempFile
            +

            Otherwise, create the file/directory by manually specifying the expected posix file permissions. For example: PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))

              diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql index c32a139f0f2d..a3faddf6ab73 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.ql @@ -1,5 +1,5 @@ /** - * @name Temporary Directory Local information disclosure + * @name Local information disclosure in a temporary directory * @description Writing information without explicit permissions to a shared temporary directory may disclose it to other users. * @kind path-problem * @problem.severity warning From 76964d58f23cef877e27e0aab1c3792cd33b0354 Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 14 Feb 2022 11:04:31 -0500 Subject: [PATCH 38/39] Apply suggestions from code review Co-authored-by: Felicity Chapman --- .../CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp index 883186f46ea8..e3bf61107c4a 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp +++ b/java/ql/src/Security/CWE/CWE-200/TempDirLocalInformationDisclosure.qhelp @@ -44,6 +44,6 @@ For example: PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePerm
            • OSWAP: Insecure Temporary File.
            • -
            • CERT: FIO00-J. Do not operate on files in shared directories
            • +
            • CERT: FIO00-J. Do not operate on files in shared directories.
            • \ No newline at end of file From 2048aed0a9dd5731ae9fd8eb4835b0bcfa0851ec Mon Sep 17 00:00:00 2001 From: Jonathan Leitschuh Date: Mon, 14 Feb 2022 11:29:16 -0500 Subject: [PATCH 39/39] Review feedback and improve temp dir vulnerable/safe code sugestion --- .../CWE/CWE-200/TempDirUsageSafe.java | 87 ++++++++++++++++++- .../CWE/CWE-200/TempDirUsageVulnerable.java | 4 + ...ile-or-directory-information-disclosure.md | 2 +- 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUsageSafe.java b/java/ql/src/Security/CWE/CWE-200/TempDirUsageSafe.java index 96227d63d454..f44ead7accbe 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUsageSafe.java +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUsageSafe.java @@ -1,3 +1,5 @@ +import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; @@ -9,11 +11,90 @@ void exampleSafe() throws IOException { Path temp2 = Files.createTempDirectory("random-directory"); // GOOD: File has permissions `drwx------` - File tempDirChildFile = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + // Creating a temporary file with a non-randomly generated name + File tempChildFile = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + // Warning: This will fail on windows as it doesn't support PosixFilePermissions. + // See `exampleSafeWithWindowsSupportFile` if your code needs to support windows and unix-like systems. Files.createFile( - tempDirChildFile.toPath(), - tempDirChild.toPath(), + tempChildFile.toPath(), PosixFilePermissions.asFileAttribute(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE)) ); // GOOD: Good has permissions `-rw-------` } + + /* + * An example of a safe use of createFile or createDirectory if your code must support windows and unix-like systems. + */ + void exampleSafeWithWindowsSupportFile() { + // Creating a temporary file with a non-randomly generated name + File tempChildFile = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); + createTempFile(tempChildFile.toPath()); // GOOD: Good has permissions `-rw-------` + } + + static void createTempFile(Path tempDir) { + try { + if (tempDirChild.getFileSystem().supportedFileAttributeViews().contains("posix")) { + // Explicit permissions setting is only required on unix-like systems because + // the temporary directory is shared between all users. + // This is not necessary on Windows, each user has their own temp directory + final EnumSet posixFilePermissions = + EnumSet.of( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE + ); + if (!Files.exists(tempDirChild)) { + Files.createFile( + tempDirChild, + PosixFilePermissions.asFileAttribute(posixFilePermissions) + ); // GOOD: Directory has permissions `-rw-------` + } else { + Files.setPosixFilePermissions( + tempDirChild, + posixFilePermissions + ); // GOOD: Good has permissions `-rw-------`, or will throw an exception if this fails + } + } else if (!Files.exists(tempDirChild)) { + // On Windows, we still need to create the directory, when it doesn't already exist. + Files.createDirectory(tempDirChild); // GOOD: Windows doesn't share the temp directory between users + } + } catch (IOException exception) { + throw new UncheckedIOException("Failed to create temp file", exception); + } + } + + void exampleSafeWithWindowsSupportDirectory() { + File tempDirChildDir = new File(System.getProperty("java.io.tmpdir"), "/child-dir"); + createTempDirectories(tempDirChildDir.toPath()); // GOOD: Directory has permissions `drwx------` + } + + static void createTempDirectories(Path tempDirChild) { + try { + if (tempDirChild.getFileSystem().supportedFileAttributeViews().contains("posix")) { + // Explicit permissions setting is only required on unix-like systems because + // the temporary directory is shared between all users. + // This is not necessary on Windows, each user has their own temp directory + final EnumSet posixFilePermissions = + EnumSet.of( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_WRITE, + PosixFilePermission.OWNER_EXECUTE + ); + if (!Files.exists(tempDirChild)) { + Files.createDirectories( + tempDirChild, + PosixFilePermissions.asFileAttribute(posixFilePermissions) + ); // GOOD: Directory has permissions `drwx------` + } else { + Files.setPosixFilePermissions( + tempDirChild, + posixFilePermissions + ); // GOOD: Good has permissions `drwx------`, or will throw an exception if this fails + } + } else if (!Files.exists(tempDirChild)) { + // On Windows, we still need to create the directory, when it doesn't already exist. + Files.createDirectories(tempDirChild); // GOOD: Windows doesn't share the temp directory between users + } + } catch (IOException exception) { + throw new UncheckedIOException("Failed to create temp dir", exception); + } + } } diff --git a/java/ql/src/Security/CWE/CWE-200/TempDirUsageVulnerable.java b/java/ql/src/Security/CWE/CWE-200/TempDirUsageVulnerable.java index a55226ad5b68..7d1d212409ea 100644 --- a/java/ql/src/Security/CWE/CWE-200/TempDirUsageVulnerable.java +++ b/java/ql/src/Security/CWE/CWE-200/TempDirUsageVulnerable.java @@ -15,5 +15,9 @@ void exampleVulnerable() { File tempDirChildFile = new File(System.getProperty("java.io.tmpdir"), "/child-create-file.txt"); Files.createFile(tempDirChildFile.toPath()); // BAD: File has permissions `-rw-r--r--` + + File tempDirChildDir = new File(System.getProperty("java.io.tmpdir"), "/child-dir"); + tempDirChildDir.mkdir(); // BAD: Directory has permissions `drwxr-xr-x` + Files.createDirectory(tempDirChildDir.toPath()); // BAD: Directory has permissions `drwxr-xr-x` } } diff --git a/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md b/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md index 8112470d2b3e..23f3a476e793 100644 --- a/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md +++ b/java/ql/src/change-notes/2022-02-04-local-temp-file-or-directory-information-disclosure.md @@ -1,6 +1,6 @@ --- category: newQuery --- -* A new query titled "Temporary directory Local information disclosure" (`java/local-temp-file-or-directory-information-disclosure`) has been added. +* A new query titled "Local information disclosure in a temporary directory" (`java/local-temp-file-or-directory-information-disclosure`) has been added. This query finds uses of APIs that leak potentially sensitive information to other local users via the system temporary directory. This query was originally [submitted as query by @JLLeitschuh](https://github.com/github/codeql/pull/4388). \ No newline at end of file