Temporary files are typically can be used to:
- Share data between processes.
- Store auxiliary program data (for example, to save preserve memory).
- Construct and/or load classes, JAR files, and native libraries dynamically.
Programmers frequently create temporary files in directories that are writable by everyone (examples are /tmp
and /var/tmp
on UNIX and C:\TEMP
on Windows). Temporary files may be purged regularly, for example, every night or during reboot. However, this allows an adversary who has access to the local file system to misuse them. An adversary can cause a program to incorrectly interpret the temporary data if temporary files are not created safely or beget a denial of service if the file is not deleted after use. For instance, if the name of the file can be predetermined, an attacker can use the time-of-check time-of-use (TOCTOU) condition to create a file with the same name leading to either a failure in creating the temporary file from within program code or the program reading a crafted file whose contents are determined by the attacker.
Mitigation strategies include the following:
1. Use other IPC mechanisms such as sockets and remote procedure calls
2. Use the low-level Java Native Interface (JNI).
3. Use memory mapped files
4. Use threads to share heap data within the same JVM (applies to data sharing between Java processes only)
5. Use a secure directory that can only be accessed by application instances (make sure that multiple instances of the application running on the same platform do not compete).
When two or more users, or a group of users, have write permission to a directory, the potential for deception is far greater than it is for shared access to a limited number of files.
Consequently, temporary files in shared directories must be:
1. Created with unique and unpredictable file names,
2. Opened with exclusive access,
3. Removed before the program exits, and
4. Opened with appropriate permissions.
Secure creation of temporary files is error prone and relies on platform dependent behavior, the Operating System and the file system being the determining factors. Code that works for a locally mounted file system, for example, may be vulnerable when used with a remotely mounted file system. Moreover, most relevant APIs are problematic. The only secure solution is to refrain from creating temporary files in shared directories.
Unique and Unpredictable filenames
Wiki Markup |
---|
A recently identified bug manifests in JRE and JDK version 6.0 and prior, wherein an attacker can predict the names of the temporary files and as a result write malicious JAR files via unknown vectors \[[CVE 08|AA. Java References#CVE 08]\]. Denial of Service attacks are also possible if unclaimed temporary resources cause rapid disk space exhaustion \[[Secunia Advisory 20132|http://secunia.com/advisories/20132/]\]. |
Noncompliant Code Example
This noncompliant code example hardcodes the name of the temporary file which implies that the name is predictable. Even though there is a built-in check to detect whether a file still exists after its creation, a TOCTOU condition exists such that an attacker can alter or delete the file before it is read.
Temporary files are files and consequently must conform to the requirements specified by other rules governing operations on files, including FIO00-J. Do not operate on files in shared directories and FIO01-J. Create files with appropriate access permissions. Temporary files have the additional requirement that they must be removed before program termination.
Removing temporary files when they are no longer required allows file names and other resources (such as secondary storage) to be recycled. Each program is responsible for ensuring that temporary files are removed during normal operation. There is no surefire method that can guarantee the removal of orphaned files in the case of abnormal termination, even in the presence of a finally
block, because the finally
block may fail to execute. For this reason, many systems employ temporary file cleaner utilities to sweep temporary directories and remove old files. Such utilities can be invoked manually by a system administrator or can be periodically invoked by a system process. However, these utilities are themselves frequently vulnerable to file-based exploits.
Noncompliant Code Example
This and subsequent code examples assume that files are created in a secure directory in compliance with FIO00-J. Do not operate on files in shared directories and are created with proper access permissions in compliance with FIO01-J. Create files with appropriate access permissions. Both requirements may be managed outside the Java Virtual Machine (JVM).
This noncompliant code example fails to remove the file upon completion:
Code Block | ||
---|---|---|
| ||
class TempFile | ||
Code Block | ||
| ||
class TempFile{ public static void main(String[] args) throws IOException{ File f = new File("tempnam.tmp"); FileOutputStream fop = new FileOutputStream(f); String str = "Data"; if(fif (f.exists()){ fop.write(str.getBytes()); } else { System.out.println("This file doesalready not existexists"); } }return; } } |
Additionally, the output stream has not been closed after use which violates FIO32-J. Ensure all resources are properly closed when they are no longer needed. Finally, the file is not deleted after use.
Exclusive Access
...
|
...
|
...
|
...
|
...
FileOutputStream |
...
fop |
...
= |
...
null; |
...
|
...
|
...
|
...
try |
...
{ |
...
|
...
|
...
|
...
|
...
|
...
fop |
...
= |
...
new FileOutputStream(f);
String str = "Data";
fop.write(str.getBytes());
} finally {
if (fop != null) {
try {
fop.close();
} catch (IOException x) {
// Handle error
}
}
}
}
}
|
Noncompliant Code Example (createTempFile()
, deleteOnExit()
)
This noncompliant code example invokes the File.createTempFile()
method, which generates a unique temporary file name based on two parameters: a prefix and an extension. This is the only method from Java 6 and earlier that is designed to produce unique file names, although the names produced can be easily predicted. A random number generator can be used to produce the prefix if a random file name is required.
This example also uses the deleteOnExit()
method to ensure that the temporary file is deleted when the JVM terminates. However, according to the Java API [API 2014] Class File
, method deleteOnExit()
documentation,
A file lock is either exclusive or shared. A shared lock prevents other concurrently-running programs from acquiring an overlapping exclusive lock, but does allow them to acquire overlapping shared locks. An exclusive lock prevents other programs from acquiring an overlapping lock of either type. Once it is released, a lock has no further effect on the locks that may be acquired by other programs.
A shared lock is useful when a file is to be read concurrently from multiple processes whereas an exclusive lock is more useful for writing. File locks cannot be used with threads within a single process. Both shared locks and exclusive locks eliminate the potential for a race condition on the locked region. The exclusive lock is similar to a mutual exclusion solution, and the shared lock eliminates race conditions by removing the potential for altering the state of the locked file region (one of the required properties for a data race).
Wiki Markup |
---|
"Whether or not a lock actually prevents another program from accessing the content of the locked region is system-dependent and consequently unspecified" \[[API 06|AA. Java References#API 06]\]. Microsoft Windows uses a file-locking mechanism called mandatory locking because every process attempting access to a locked file region is subject to the restriction. Linux implements mandatory locks and advisory locks. An advisory lock is not enforced by the operating system, which severely diminishes its value from a security perspective. Unfortunately, the mandatory file lock in Linux is also largely impractical for the following reasons: |
1. Mandatory locking works only on local file systems and does not extend to network file systems (such as NFS or AFS)
2. File systems must be mounted with support for mandatory locking, and this is disabled by default
3. Locking relies on the group ID bit that can be turned off by another process (thereby defeating the lock)
Removal Before Termination
Removing temporary files when they are no longer required allows file names and other resources (such as secondary storage) to be recycled. In the case of abnormal termination (even in the presence of a finally
block that does not get a chance to execute), there is no surefire method that can guarantee the removal of orphaned files. For this reason, temporary file cleaner utilities, which are invoked manually by a system administrator or periodically run by a daemon to sweep temporary directories and remove old files, are widely used. However, these utilities are themselves vulnerable to file-based exploits and often require the use of shared directories. During normal operation, it is the responsibility of the program to ensure that temporary files are removed appropriately.
Noncompliant Code Example
This noncompliant code example improves over the previous noncompliant code example by demonstrating how the method File.createTempFile()
can be used to generate a unique temporary filename based on two parameters, a prefix and an extension. Currently, this is the only method that is designed for producing unique file names but even then, the names produced are not hard to predict. It is recommended that the prefix be generated using a good random number generator.
According to the Java API \[[API 06|AA. Java References#API 06]\] Class {{File}}, method {{deleteOnExit()}} documentation: Wiki Markup
Deletion will be attempted only for normal termination of the virtual machine, as defined by the Java Language Specification. Once deletion has been requested, it is not possible to cancel the request. This method should consequently therefore be used with care.
Note: this method should not be used for file-locking, as the resulting protocol cannot be made to work reliably.
This implies that the file would not be deleted if the JVM terminates unexpectedly. Another longstanding bug that remains unresolved violates the temporary file deletion contract provided by the {{deleteOnExit()}} method. If a stream or a {{RandomAccessFile}} is left unclosed before calling {{deleteOnExit()}}, the file is not deleted on Windows based systems \[[Bug ID: 4171239|http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4171239]\]. Consequently, the file is not deleted if the JVM terminates unexpectedly. A longstanding bug on Windows-based systems, reported as Bug ID: 4171239 [SDN 2008], causes JVMs to fail to delete a file when Wiki Markup deleteOnExit()
is invoked before the associated stream or RandomAccessFile
is closed.
Code Block | ||
---|---|---|
| ||
class TempFile { public static void main(String[] args) throws IOException{ File f = File.createTempFile("tempnam",".tmp"); FileOutputStream fop = null; try { fop = new FileOutputStream(f); String str = "Data"; try { fop.write(str.getBytes()); fop.flush(); } finally { // Stream/file is not closed first, file will still open; file will // not be deleted on Windows systems f.deleteOnExit(); // Delete the file when the JVM terminates if (fop != null) { try { fop.close(); } catch (IOException x) { // Handle error } } } } } |
Compliant Solution
...
Wiki Markup |
---|
As a workaround to the file/stream termination issue described above, always try to terminate the resource first. This should have been done using {{fop.close()}} in the noncompliant code example. It is also recommended that {{File.io.delete()}} be used to immediately delete the file to avoid improper JVM termination related issues. Moreover, although unreliable, {{System.gc()}} may be invoked to free up related resources. Sometimes, it is not possible to close the resources on which the delete operation has to be invoked \[[Bug ID: 4635827|http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4635827]\]. Currently, there is no way to handle this case. It is highly recommended that temporary files be created only in secure directories. |
Risk Assessment
(DELETE_ON_CLOSE
)
This compliant solution creates a temporary file using several methods from Java's NIO.2 package (introduced in Java SE 7). It uses the createTempFile()
method, which creates an unpredictable name. (The actual method by which the name is created is implementation-defined and undocumented.) The file is opened using the try
-with-resources construct, which automatically closes the file regardless of whether an exception occurs. Finally, the file is opened with the DELETE_ON_CLOSE
option, which removes the file automatically when it is closed.
Code Block | ||
---|---|---|
| ||
class TempFile {
public static void main(String[] args) {
Path tempFile = null;
try {
tempFile = Files.createTempFile("tempnam", ".tmp");
try (BufferedWriter writer =
Files.newBufferedWriter(tempFile, Charset.forName("UTF8"),
StandardOpenOption.DELETE_ON_CLOSE)) {
// Write to file
}
System.out.println("Temporary file write done, file erased");
} catch (FileAlreadyExistsException x) {
System.err.println("File exists: " + tempFile);
} catch (IOException x) {
// Some other sort of failure, such as permissions.
System.err.println("Error creating temporary file: " + x);
}
}
}
|
Compliant Solution
When a secure directory for storing temporary files is not available, the vulnerabilities that result from using temporary files in insecure directories can be avoided by using alternative mechanisms, including
- Other IPC mechanisms such as sockets and remote procedure calls.
- The low-level Java Native Interface (JNI).
- Memory-mapped files.
- Threads to share heap data within the same JVM (applies to data sharing between Java processes only).
Risk Assessment
Failure to remove temporary files before termination can result in information leakage and resource exhaustionNot following the best practices while creating, using and deleting temporary files can lead to denial of service vulnerabilities, misinterpretations and alterations in control flow.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|
FIO03-J |
Medium |
Probable |
Medium |
P8 |
L2 |
Automated Detection
...
TODO
Related Vulnerabilities
Other Languages
...
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Parasoft Jtest |
| CERT.FIO03.ATF CERT.FIO03.REMTMP | Avoid temporary files Remove temporary files before termination |
Related Guidelines
...
...
...
...
...
...
...
Wiki Markup |
---|
\[[API 06|AA. Java References#API 06]\] Class File, methods {{createTempFile}}, {{delete}}, {{deleteOnExit}}
\[[Darwin 04|AA. Java References#Darwin 04]\] 11.5 Creating a Transient File
\[[SDN 08|AA. Java References#SDN 08]\] Bug IDs: 4171239, 4405521, 4635827, 4631820
\[[Secunia 08|AA. Java References#Secunia 08]\] [Secunia Advisory 20132|http://secunia.com/advisories/20132/]
\[[CVE 08|AA. Java References#CVE 08]\] [CVE-2008-5354|http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2008-5354]
\[[MITRE 09|AA. Java References#MITRE 09]\] [CWE ID 459 |http://cwe.mitre.org/data/definitions/459.html] "Incomplete Cleanup", [CWE ID 377|http://cwe.mitre.org/data/definitions/377.html] "Insecure Temporary File" |
Bibliography
[API 2014] |
|
Section 11.5, "Creating a Transient File" | |
Bug JDK-4405521 | |
[SDN 2008] | Bug ID: 4171239 |
...
FIO33-J. Exclude user input from format strings 09. Input Output (FIO) FIO05-J. Do not create multiple buffered wrappers on an InputStream