You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 27 Next »

Temporary files are typically used to:

  • Share data between processes
  • Store auxiliary program data (to save 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

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]]. Denial of Service attacks are also possible if unclaimed temporary resources cause rapid disk space exhaustion [Secunia Advisory 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.

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(f.exists()){
      fop.write(str.getBytes());
    } else { 
      System.out.println("This file does not exist"); 
    }
  }      
}

Additionally, the output stream has not been closed after use which violates FIO06-J. Ensure all resources are properly closed when they are no longer needed. Finally, the file is not deleted after use.

Exclusive Access

Exclusive access grants unrestricted file access to the locking process while denying access to all other processes and eliminates the potential for a race condition on the locked region. Files, or regions of files, can be locked to prevent two processes from concurrent access. The java.nio.channels.FileLock class facilitates file locking. According to the Java API [[API 06]] 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).

"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]]. 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]] Class File, method deleteOnExit() documentation:

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 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].

class TempFile{
  public static void main(String[] args) throws IOException{
    File f = File.createTempFile("tempnam",".tmp");
    FileOutputStream fop = new FileOutputStream(f);
    String str = "Data";
    try {
      fop.write(str.getBytes());
      fop.flush();        
    }finally {
      // Stream/file is not closed first, file will not be deleted
      f.deleteOnExit(); // Delete the file when the JVM terminates
    }
  }       
}

Compliant Solution

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]. Currently, there is no way to handle this case. It is highly recommended that temporary files be created only in secure directories.

Risk Assessment

Not 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

FIO34- J

high

probable

medium

P12

L1

Automated Detection

TODO

Related Vulnerabilities

GERONIMO-3489

Other Languages

This rule appears in the C Secure Coding Standard as FIO43-C. Do not create temporary files in shared directories.

This rule appears in the C++ Secure Coding Standard as FIO43-CPP. Do not create temporary files in shared directories.

References

[[API 06]] Class File, methods createTempFile, delete, deleteOnExit
[[Darwin 04]] 11.5 Creating a Transient File
[[SDN 08]] Bug IDs: 4171239, 4405521, 4635827, 4631820
[[Secunia 08]] Secunia Advisory 20132
[[CVE 08]] CVE-2008-5354
[[MITRE 09]] CWE ID 459 "Incomplete Cleanup", CWE ID 377 "Insecure Temporary File"


FIO33-J. Exclude user input from format strings      09. Input Output (FIO)      FIO05-J. Do not create multiple buffered wrappers on an InputStream

  • No labels