...
Conformance of File Functions to Criteria for Temporary Files
|
|
|
|
|
| |
|---|---|---|---|---|---|---|
Unpredictable Name | Not portably | Yes | Not portably | Yes | Not portably | Not portably |
Unique Name | Yes | Yes | Yes | Yes | Yes | Yes |
Atomic open | No | No | Yes | Yes | No | Yes |
Exclusive AccessPossible | Possible | No | If supported by OS | Possible | If supported by OS | |
Appropriate Permissions | Possible | Possible | If supported by OS* | If supported by OS | Possible | Not portably |
File Removed | No | No | Yes* | Yes* | No | No |
* If the program terminates abnormally, this behavior is implementation-defined.
...
O_SHLOCK: Atomically obtain a shared lock.O_EXLOCK: Atomically obtain an exclusive lock.
Noncompliant Code Example (
...
mktemp()/open(),
...
POSIX)
The C Standard function tmpnam_sThe POSIX function mktemp() function generates a string that is a valid takes a given file name and that is not the same as the name of an existing file. It is almost identical to the tmpnam() function except for an added maxsize argument for the supplied buffer.template and overwrites a portion of it to create a file name. The template may be any file name with exactly six X's appended to it (for example, /tmp/temp.XXXXXX). The six trailing X's are replaced with the current process number and/or a unique letter combination.
| Code Block | ||||
|---|---|---|---|---|
| ||||
| Code Block | ||||
| ||||
#define __STDC_WANT_LIB_EXT1__#include <stdio.h> #include <stdio<stdlib.h> void func(void) { char file_name[L_tmpnam_s]] = "tmp-XXXXXX"; int fd; if (tmpnam_s!mktemp(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 */ } } |
Nonnormative text in the C Standard, subclause K.3.5.1.2 [ISO/IEC 9899:2011], also recommends the following:
Implementations should take care in choosing the patterns used for names returned by
tmpnam_s. For example, making a thread id part of the names avoids the race condition and possible conflict when multiple programs run simultaneously by the same user generate the same temporary file names.
If implemented, the space for unique names is reduced and the predictability of the resulting names is increased. In general, Annex K does not establish any criteria for the predictability of names. For example, the name generated by the tmpnam_s function from Microsoft Visual Studio 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).
Noncompliant 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 exactly six X's appended to it (for example, /tmp/temp.XXXXXX). The six trailing X's are replaced with the current process number and/or a unique letter combination.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h>
#include <stdlib.h>
void func(void) {
char file_name[] = "tmp-XXXXXX";
int fd;
if (!mktemp(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 */
}
} |
The mktemp() function is marked "LEGACY" in the Open Group Base Specifications Issue 6 [Open Group 2004]. The manual page for mktemp() gives more detail:
Never use
mktemp(). Some implementations follow BSD 4.3 and replaceXXXXXXby 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 ofmktemp()is a security risk. The race is avoided bymkstemp(3).
Noncompliant Code Example (tmpfile())
The 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.
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().) Subclause 7.21.4.4, paragraph 6, of the C Standard allows for the value of the macro TMP_MAX to be as small as 25.
Most historic implementations provide only a limited number of possible temporary file names (usually 26) before file names are recycled.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#include <stdio.h>
void func(void) {
FILE *fp = tmpfile();
if (fp == NULL) {
/* Handle error */
}
} |
Noncompliant Code Example (tmpfile_s(), Annex K)
The tmpfile_s() function creates a temporary binary file that is different from any other existing file and 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.
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.
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 required to be only 25 [ISO/IEC 9899:2011].
The C Standard, subclause K3.5.1.2, paragraph 7, notes the following regarding the use of tmpfile_s() instead of tmpnam_s() [ISO/IEC 9899:2011]:
...
The mktemp() function is marked "LEGACY" in the Open Group Base Specifications Issue 6 [Open Group 2004]. The manual page for mktemp() gives more detail:
Never use
mktemp(). Some implementations follow BSD 4.3 and replaceXXXXXXby 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 ofmktemp()is a security risk. The race is avoided bymkstemp(3).
Noncompliant Code Example (tmpfile())
The 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.
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().) Subclause 7.21.4.4, paragraph 6, of the C Standard allows for the value of the macro TMP_MAX to be as small as 25.
Most historic implementations provide only a limited number of possible temporary file names (usually 26) before file names are recycled.
| Code Block | ||||
|---|---|---|---|---|
| ||||
#define __STDC_WANT_LIB_EXT1__ #include <stdio.h> void func(void) { FILE *fp *fp = tmpfile(); if (tmpfile_s(&fp == NULL)) { /* Handle error */ } } |
...
* Handle error */
}
} |
Compliant Solution (mkstemp(), POSIX)
...
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 process ID 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].
...
FIO21-C-EX1: The Annex K tmpfile_s() function can be used if all the targeted implementations create temporary files in secure directories.
Risk Assessment
Insecure temporary file creation can lead to a program accessing unintended files and permission escalation on local systems.
Recommendation | Severity | Likelihood | Detectable | RepairableRemediation Cost | Priority | Level |
|---|---|---|---|---|---|---|
FIO21-C | Medium | Probable | No | MediumNo | P8P4 | L2L3 |
Automated Detection
Tool | Version | Checker | Description | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
| CodeSonar |
| BADFUNC.TEMP.* BADFUNC.TMPFILE_S BADFUNC.TMPNAM_S | A collection of checks that report uses of library functions associated with temporary file vulnerabilities Use of tmpfile_s Use of tmpnam_s | |||||||
| Compass/ROSE | Can detect violations of this recommendation. Specifically, Rose reports use of | |||||||||
| Coverity | 6.5 | SECURE_TEMP | Fully implemented | |||||||
| Helix QAC |
| C5016 | ||||||||
| LDRA tool suite |
| 44 S | Enhanced enforcement | |||||||
| Parasoft C/C++test |
| CERT_C-FIO21- | ab | Use secure temporary file name functions | ||||||
| Polyspace Bug Finder |
| CERT C: Rec. FIO21-C | Checks for non-secure temporary file (rec. partially covered) | |||||||
| Security Reviewer - Static Reviewer |
| C76 | Fully implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
| [HP 2003] | |
| [IEEE Std 1003.1:2013] | XSH, System Interfaces: openXSH, System Interfaces: mkdopen, mksopen |
[ISO/IEC 9899:2011]Subclause K.3.5.1.2, "The tmpnam_s Function" | Subclause 7.21.4.4, "The tmpnam Function" |
| [Kennaway 2000] | |
| [Open Group 2004] | open() |
| [Seacord 2013] | Chapter 3, "Pointer Subterfuge" Chapter 8, "File I/O" |
| [Viega 2003] | Section 2.1, "Creating Files for Temporary Use" |
| [Wheeler 2003] | Chapter 7, "Structure Program Internals and Approach" |
...