Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Programmers frequently create temporary files . Commonly, temporary file in directories that are writable by everyone (examples being /tmp and /var/tmp on UNIX, and C:\TEMP on Windows) and may be purged regularly (for example, every night or during reboot).

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 few files.

Temporary files are commonly used:

  • For auxiliary storage for data that does not need to, or otherwise cannot, reside in memory
  • As a means of communicating with other processes by transferring data through the file system

When temporary files are needed for storage, they should be created either in a secure directory (see FIO17-A. Ensure that file operations are performed in a secure directory) or jail (see FIO16-A. Limit access to files by creating a jail). This will help protect these files from unintended access by attackers.

Temporary files are also used to communicate between two or more collaborating processes. For example, one process will create a temporary file in a shared directory with a well-known name, or a temporary name that is then communicated between processes. The file then can be used to share information among these collaborating processes.

This is a dangerous practice, because a well known file in a shared directory can be easily hijacked or manipulated by an attacker. Mitigation strategies include:

1. Use other low-level IPC mechanisms such as sockets or shared memory.
2. Use higher level IPC mechanisms such as remote procedure calls.
3. Use a secure directory or a jail that can only be accessed by application instances (making sure that multiple instances of the application running on the same platform do not compete).

There are many different interprocess communication (IPC) mechanisms, some of which require the use of temporary files, while others do not. An example of an IPC mechanism that uses temporary files is the POSIX mmap() function. Berkley Sockets, POSIX Local IPC Sockets and System V Shared Memory do not require temporary files. Because the multiuser nature of shared directories poses an inherent security risk, the use of shared temporary files for IPC is discouraged.

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 few files.

Consequently, temporary files Consequently, temporary files 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.

...

 

tmpnam
(C99)

tmpnam_s
(ISO/IEC TR 24731-1)

tmpfile
(C99)

tmpfile_s
(ISO/IEC TR 24731-1)

mktemp
(POSIX)

mkstemp
(POSIX)

Unpredictable name Name

Not portably

Yes

Not portably

Yes

Not portably

Not portably

Unique Name

Yes

Yes

Yes

Yes

Yes

Yes

Atomic

No

No

Yes

Yes

No

Yes

Exclusive Access

Possible

Possible

No

If supported by OS

Possible

If supported by OS

Appropriate Permissions

Possible

Possible

No

If supported by OS

Possible

Not portably

File Removed

No

No

Yes*

Yes*

No

No

...

Securely creating temporary files is error prone and dependent on the version of the C runtime library used, the operating system, and the file system. Code that works for a locally mounted file system, for example, may be vulnerable when used with a remotely mounted file system. Moreover, none of these functions are without problems. The best advice only secure solution is not to create temporary files in shared directories (see FIO15-A. Do not create temporary files in shared directories). In cases where it is absolutely necessary to do so, the tmpfile_s() and mkstemp() functions provide the most secure solutionsdirectories.

Unique and Unpredictable File Names

Wiki Markup
Privileged programs that create temporary files in world-writable directories can be exploited to overwrite protected system files. An attacker who can predict the name of a file created by a privileged program can create a symbolic link (with the same name as the file used by the program) to point to a protected system file. Unless the privileged program is coded securely, the program will follow the symbolic link instead of opening or creating the file that it is supposed to be using. As a result, a protected system file to which the symbolic link points can be overwritten when the program is executed \[[HP 03|AA. C References#HP 03]\]. Unprivileged programs can be similarly exploited to overwrite protected user files.

Exclusive Access

Wiki Markup
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 (see \[[Seacord 05a|AA. C References#Seacord 05]\] Chapter 7).

...

  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, there is no sure 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 (see FIO15-A. Do not create temporary files in shared directories). During normal operation, it is the responsibility of the program to ensure that temporary files are removed either explicitly, or through the use of library routines such as tmpfile_s which guarantee temporary file deletion upon program termination.

Non-Compliant Code Example: fopen()/open() with tmpnam()

The following This non-compliant code example creates a file with a hard coded file_name (presumably in a shared directory such as /tmp or C:\Temp).

...

  • O_SHLOCK Atomically obtain a shared lock.
  • O_EXLOCK Atomically obtain an exclusive lock.

Non-Compliant Code Example: tmpnam_s() (ISO/IEC TR 24731-1)

Wiki Markup
The TR 24731-1 {{tmpnam_s()}} function generates a string that is a valid file name and that is not the same as the name of an existing file \[[ISO/IEC TR 24731-1:2007|AA. C References#SO/IEC TR 24731-1-2007]\]. It is almost identical to the {{tmpnam}} function above except with an added {{maxsize}} argument for the supplied buffer.

...

If implemented, this reduces the space for unique names and increases the predictability of the resulting names. But in general, TR 24731-1 does not establish any criteria for the predictability of names. For example, the name generated by the tmpnam_s function from Microsoft Visual Studio 2005 consists of a program-generated file name and, after the first call to tmpnam_s(), a file extension of sequential numbers in base 32 (.1-.1vvvvvu, when TMP_MAX_S in stdio.h is INT_MAX).

Non-Compliant Code Example: mktemp()/open() (POSIX)

The POSIX function mktemp() takes a given file name template and overwrites a portion of it to create a file name. The template may be any file name with some number of Xs appended to it (for example, /tmp/temp.XXXXXX). The trailing Xs are replaced with the current process number and/or a unique letter combination. The number of unique file names mktemp() can return depends on the number of Xs provided.

...

Never use mktemp(). Some implementations follow BSD 4.3 and replace XXXXXX by the current process id and a single letter, so that at most 26 different names can be returned. Since on the one hand the names are easy to guess, and on the other hand there is a race between testing whether the name exists and opening the file, every use of mktemp() is a security risk. The race is avoided by mkstemp(3).

Non-Compliant Code Example: tmpfile()

The C99 tmpfile() function creates a temporary binary file that is different from any other existing file and that is automatically removed when it is closed or at program termination.

...

Code Block
bgColor#FFCCCC
FILE* fp = tmpfile();
if (fp == NULL) {
  /* Handle error */
}

Non-Compliant Code Example: tmpfile_s() (ISO/IEC TR 24731-1)

The ISO/IEC TR 24731-1 function tmpfile_s() creates a temporary binary file that is different from any other existing file and that is automatically removed when it is closed or at program termination. If the program terminates abnormally, whether an open temporary file is removed is implementation-defined.

...

After a program obtains a file name using the tmpnam_s function and before the program creates a file with that name, the possibility exists that someone else may create a file with that same name. To avoid this race condition, the tmpfile_s function should be used instead of tmpnam_s when possible. One situation that requires the use of the tmpnam_s function is when the program needs to create a temporary directory rather than a temporary file.

Code Block
bgColor#FFCCCC

if (tmpfile_s(&fp)) {
  /* Handle error */
}

The TR24731-1 tmpfile_s() function should not be used with implementations that create temporary files in shared directory such as /tmp or C: because the function does not allow the user to specify a directory in which the temporary file should be created (see FIO15-A. Do not create temporary files in shared directories).

Compliant Solution: mkstemp() (POSIX)

A reasonably secure solution for generating random file names is to use the mkstemp() function. The mkstemp() function is available on systems that support the Open Group Base Specifications Issue 4, Version 2 or later.

A call to mkstemp() replaces the six Xs in the template string with six randomly selected characters and returns a file descriptor for the file (opened for reading and writing):

...

One situation that requires the use of the tmpnam_s function is when the program needs to create a temporary directory rather than a temporary file.

Code Block
bgColor#FFCCCC

if (tmpfile_s(&fp)) {
  /* Handle error */
}

The TR24731-1 tmpfile_s() function should not be used with implementations that create temporary files in shared directory such as /tmp or C: because the function does not allow the user to specify a directory in which the temporary file should be created (see FIO15-A. Do not create temporary files in shared directories).

Compliant Solution: mkstemp() (POSIX)

...

The mkstemp() algorithm for selecting file names has proven to be immune to attacks. This solution is not serially reusable, however, because the The mkstemp() function is available on systems that support the Open Group Base Specifications Issue 4, Version 2 or later.

A call to mkstemp() function replaces the "XXXXXX" six Xs in template the first it is invoked. This is not a problem, as long as template is reinitialized before calling mkstemp() again. If template is not reinitialized, the mkstemp() function will return -1 and leave template unmodified because template did not contain six X'sthe template string with six randomly selected characters and returns a file descriptor for the file (opened for reading and writing) as in this compliant solution.

Code Block
bgColor#ccccff
char const *sdn = "/home/usr1/";
char sfn[] = "/home/usr1/temp-XXXXXX";
FILE *sfp;

if (!secure_dir(sdn)) {
  /* Handle error */
}

int fd = mkstemp(sfn);
if (fd == -1) {
  /* Handle error */
}

/*
 * Unlink immediately to hide the file name.
 * The race condition here is inconsequential if the file
 * is created with exclusive permissions (glibc >= 2.0.7)
 */

unlink(sfn);

sfp = fdopen(fd, "w+");
if (sfp == NULL) {
  close(fd);
  /* Handle error */
}

/* use temporary file */

fclose(sfp); /* also closes fd */
 */
}

/* use temporary file */

fclose(sfp); /* also closes fd */

This solution is not serially reusable, however, because the mkstemp() function replaces the "XXXXXX" in template the first it is invoked. This is not a problem, as long as template is reinitialized before calling mkstemp() again. If template is not reinitialized, the mkstemp() function will return -1 and leave template unmodified because template did not contain six X's.

Wiki Markup
The Open Group Base Specification Issue 6 \[[Open Group 04|AA. C References#Open Group 04]\] does not specify the permissions the file is created with, so these are [implementation-defined|BB. Definitions#implementation-defined behavior]. However, Issue 7 (POSIX.1-2008) specifies them as {{S_IRUSR\|S_IWUSR}} (0600) \[[Austin Group 08|AA. C References#Austin Group 08]\].

This compliant solution invokes the an implementation secure_dir(} function (such as the one defined in FIO17-A. Ensure that file operations are performed in a secure directory) to ensure the temporary file resides in a secure directory.

Implementation Details

For glibc versions 2.0.6 and earlier, the file is created with permissions 0666; for glibc versions 2.0.7 and later, the file is created with permissions 0600. On NetBSD, the file is created with permissions 0600. This creates a security risk in that an attacker will have write access to the file immediately after creation. Consequently, programs need a private version of the mkstemp() function in which this issue is known to be fixed.

Wiki Markup
In many older [implementations|BB. Definitions#implementation], the name is a function of process ID and time, so it is possible for the attacker to predict the name and create a decoy in advance.  FreeBSD has recently changed the {{mk*temp()}} family to eliminate the PID component of the file name and replace the entire field with base-62 encoded randomness.  This raises the number of possible temporary files for the typical use of 6 Xs significantly, meaning that even {{mktemp()}} with 6 Xs is reasonably (probabilistically) secure against guessing, except under frequent usage \[[Kennaway 00|AA. C References#Kennaway 00]\].

Risk Assessment

Failure to create unique, unpredictable temporary file names can make it possible for an attacker to access or modify privileged files.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO43-C

high

probable

medium

P12

L1

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Automated Detection

Compass/ROSE is able to detect violations of this recommendation. Specifically, Rose reports use of tmpnam(), tmpnam_s(), tmpfile(), and mktemp().

References

Wiki Markup
\[[Austin Group 08|AA. C References#Austin Group 08]\]
\[[HP 03|AA. C References#HP 03]\]
\[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\] Sections 7.19.4.4, "The {{tmpnam}} function," 7.19.4.3, "The {{tmpfile}} function," and 7.19.5.3, "The {{fopen}} function"
\[[ISO/IEC PDTR 24772|AA. C References#ISO/IEC PDTR 24772]\] "EWR Path Traversal"
\[[ISO/IEC TR 24731-1:2007|AA. C References#ISO/IEC TR 24731-1-2007]\] Sections 6.5.1.2, "The {{tmpnam_s}} function," 6.5.1.1, "The {{tmpfile_s}} function," and 6.5.2.1, "The {{fopen_s}} function"
\[[Kennaway 00|AA. C References#Kennaway 00]\]
\[[Open Group 04|AA. C References#Open Group 04]\] [{{mktemp()}}|http://www.opengroup.org/onlinepubs/000095399/functions/mktemp.html], [{{mkstemp()}}|http://www.opengroup.org/onlinepubs/009695399/functions/mkstemp.html], [{{open()}}|http://www.opengroup.org/onlinepubs/009695399/functions/open.html]
\[[Seacord 05a|AA. C References#Seacord 05a]\] Chapter 3, "File I/O", Chapter 7
\[[Viega 03|AA. C References#Viega 03]\] Section 2.1, "Creating Files for Temporary Use"
\[[Wheeler 03|AA. C References#Wheeler 03]\] [Chapter 7, "Structure Program Internals and Approach"|http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/avoid-race.html#TEMPORARY-FILES]

...