...
Unique and Unpredictable File Names
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 2003|AA. Bibliography#HP 03]\]. Unprivileged programs can be similarly exploited to overwrite protected user files. Wiki Markup
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. (See \ [[Seacord 2005a|AA. Bibliography#Seacord 05] \] Chapter 7.) Wiki Markup
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.
The following noncompliant code example attempts to remedy the problem by generating the file name at runtime using {{ Wiki Markup 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 | ||||
---|---|---|---|---|
| ||||
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.
This next noncompliant code example attempts to remedy the problem by using the POSIX {{ Wiki Markup 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 | ||||
---|---|---|---|---|
| ||||
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.
Care should be observed when using {{ Wiki Markup 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)
The TR 24731-1 {{ Wiki Markup 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 | ||||
---|---|---|---|---|
| ||||
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, thetmpfile_s
function should be used instead oftmpnam_s
when possible. One situation that requires the use of thetmpnam_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.
The 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 {{ Wiki Markup 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.
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 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 Wiki Markup 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 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
|
| ||||||||||||
|
|
|
|
...
MITRE CWE: CWE ID 379, "Creation of Temporary File in Directory with Insecure Permissions"
Bibliography
\[[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] Wiki Markup
[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)