Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 4.0

...

Unique and Unpredictable File Names

Wiki MarkupPrivileged 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 2003|AA. Bibliography#HP 03]\]. Unprivileged programs can be similarly exploited to overwrite protected user files.

Exclusive Access

Wiki MarkupExclusive 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 2005a|AA. Bibliography#Seacord 05] \] Chapter 7.)

Files, or regions of files, can be locked to prevent two processes from concurrent access. Windows supports two types of file locks:

...

Because the name is hard coded and consequently neither unique nor unpredictable, an attacker need only replace a file with a symbolic link, and the target file referenced by the link is opened and truncated.

Wiki MarkupThe following noncompliant code example attempts to remedy the problem by generating the file name at runtime using {{tmpnam()}}. The C99 {{tmpnam()}} 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 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\]. Files created using strings generated by the {{tmpnam()}} function are temporary in that their names should not collide with those generated by conventional naming rules for the [implementation|BB. Definitions#implementation]. The function is potentially capable of generating {{TMP_MAX}} different strings, but any or all of them may already be in use by existing files.

Code Block
bgColor#FFCCCC
langc
char file_name[L_tmpnam];
FILE* fp;

if (!tmpnam(file_name)) {
  /* Handle error */
}

/* A TOCTOU race condition exists here */

fp = fopen(file_name, "wb+");
if (fp == NULL) {
   /* Handle error */
}

Because tmpnam() does not guarantee a unique name and fopen() does not provide a facility for an exclusive open, this code is still vulnerable.

Wiki MarkupThis next noncompliant code example attempts to remedy the problem by using the POSIX {{open()}} function and providing a mechanism to indicate whether an existing file has been opened for writing or a new file has been created \ [[Open Group 2004|AA. Bibliography#Open Group 04]\]. If the {{O_CREAT}} and {{O_EXCL}} flags are used together, the {{open()}} function fails when the file specified by {{file_name}} already exists. To prevent an existing file from being opened and truncated, include the flags {{O_CREAT}} and {{O_EXCL}} when calling {{ when calling open()}}.

Code Block
bgColor#FFCCCC
langc
char file_name[L_tmpnam];
int fd;

if (!(tmpnam(file_name))) {
  /* Handle error */
}

/* A TOCTOU race condition exists here */

fd = open(file_name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0600);
if (fd < 0) {
   /* Handle error */
}

This call to open() fails whenever file_name already exists, including when it is a symbolic link, but a temporary file is presumably still required. Additionally, the method used by tmpnam() to generate file names is not guaranteed to be unpredictable, which leaves room for an attacker to guess the file name ahead of time.

Wiki MarkupCare should be observed when using {{O_EXCL}} with remote file systems because it does not work with NFS version 2. NFS version 3 added support for {{O_EXCL}} mode in {{open()}}; see IETF RFC 1813 \ [[Callaghan 1995|AA. Bibliography#Callaghan 95]\], particularly the {{EXCLUSIVE}} value to the {{mode}} argument of {{CREATE}}.unmigrated-wiki-markup

Moreover, the {{open()}} function, as specified by the Open Group Base Specifications Issue 6 \ [[Open Group 2004|AA. Bibliography#Open Group 04]\], does not include support for shared or exclusive locks. However, BSD systems support two additional flags that allow you to obtain these locks:

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

Noncompliant Code Example (tmpnam_s(), ISO/IEC TR 24731-1)

Wiki MarkupThe 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. Bibliography#SO/IEC TR 24731-1-2007]\]. It is almost identical to the {{tmpnam()}} function function, except for an added {{maxsize}} argument for the supplied buffer.

Code Block
bgColor#FFCCCC
langc
char file_name[L_tmpnam_s];
int fd;

if (tmpnam_s(file_name, L_tmpnam_s) != 0) {
  /* Handle error */
}

/* A TOCTOU race condition exists here */
fd = open(file_name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0600);
if (fd < 0) {
  /* Handle error */
}

...

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.unmigrated-wiki-markup

It should be possible to open at least {{TMP_MAX}} temporary files during the lifetime of the program. (This limit may be shared with {{tmpnam()}}.) C99, Section 7.19.4.4, allows for the value of the macro {{TMP_MAX}} to be as small as 25 \ [[ISO/IEC 9899:1999|AA. Bibliography#ISO/IEC 9899-1999]\].

Most historic implementations provide only a limited number of possible temporary file names (usually 26) before file names are recycled.

...

The file is opened for update with "wb+" mode, which means "truncate to zero length or create binary file for update." To the extent that the underlying system supports the concepts, the file is opened with exclusive (nonshared) access and has a file permission that prevents other users on the system from accessing the file.unmigrated-wiki-markup

It should be possible to open at least {{TMP_MAX_S}} temporary files during the lifetime of the program. (This limit may be shared with {{tmpnam_s()}}.) The value of the macro {{TMP_MAX_S}} is only required to be 25 \[ [ISO/IEC TR 24731-1:2007|AA. Bibliography#ISO/IEC TR 24731-1-2007]\].unmigrated-wiki-markup

TR 24731-1 notes the following regarding the use of {{tmpfile_s()}} instead of {{tmpnam_s()}} \ [[ISO/IEC TR 24731-1:2007|AA. Bibliography#ISO/IEC TR 24731-1-2007]\]:

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.

...

This solution is not serially reusable; however, because the mkstemp() function replaces the "XXXXXX" in template the first time 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 MarkupThe Open Group Base Specification Issue 6 \[ [Open Group 2004|AA. Bibliography#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 2008|AA. Bibliography#Austin Group 08]\].

This compliant solution invokes the user-defined function secure_dir()} (such as the one defined in recommendation FIO15-C. Ensure that file operations are performed in a secure directory) to ensure the temporary file resides in a secure directory.

...

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 MarkupIn 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 changed the {{In many older implementations, 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 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 six {{X}}'s significantly, meaning that even {{mktemp()}} with six {{X}}'s is reasonably (probabilistically) secure against guessing, except under frequent usage \[ [Kennaway 2000|AA. Bibliography#Kennaway 00]\].

Exceptions

FIO43-EX1: The TR24731-1 tmpfile_s() function can be used if all the targeted implementations create temporary files in secure directories.

...

Tool

Version

Checker

Description

Section

Compass/ROSE

 

 

Section

can detect violations of this recommendation. Specifically, Rose reports use of tmpnam(), tmpnam_s(), tmpfile(), and mktemp()

Section

LDRA tool suite

Include Page
c:LDRA_Vc:
LDRA_V
Section

489 S

Section

Partially Implemented

...

MITRE CWE: CWE ID 379, "Creation of Temporary File in Directory with Insecure Permissions"

Bibliography

Wiki Markup\[[Austin Group 2008|AA. Bibliography#Austin Group 08]\] \[[HP 2003|AA. Bibliography#HP 03]\] \[[Kennaway 2000|AA. Bibliography#Kennaway 00]\] \[[Open Group 2004|AA. Bibliography#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 2005a|AA. Bibliography#Seacord 05a]\] Chapter 3, "File I/O", Chapter 7 \[[Viega 2003|AA. Bibliography#Viega 03]\] Section 2.1, "Creating Files for Temporary Use" \[[Wheeler 2003|AA. Bibliography#Wheeler 03]\] [Chapter 7, "Structure Program Internals and Approach"|http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/avoid-race.html#TEMPORARY-FILES]2008]
[HP 2003]
[Kennaway 2000]
[Open Group 2004] mktemp(), mkstemp(), open()
[Seacord 2005a] Chapter 3, "File I/O", Chapter 7
[Viega 2003] Section 2.1, "Creating Files for Temporary Use"
[Wheeler 2003] Chapter 7, "Structure Program Internals and Approach"

...

FIO42-C. Ensure files are properly closed when they are no longer needed      09. Input Output (FIO)