...
- created unpredictable file names.
- created with unique names.
- opened only if the file doesn't already exist (atomic open).
- opened with exclusive access.
- opened with appropriate permissions.
- removed before the program exits.
The following table lists common temporary file functions and their respective conformance to these criteria:
...
This noncompliant code example creates a file with a hard-coded file_name
(presumably in a shared directory such as /tmp
or C:\Temp
).:
Code Block | ||||
---|---|---|---|---|
| ||||
char file_name[] = /* hard coded string */; FILE *fp = fopen(file_name, "wb+"); if (fp == NULL) { /* Handle error */ } |
...
The 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]. 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 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 */ } |
...
A call to mkstemp()
replaces the six X
's in the 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 | ||||
---|---|---|---|---|
| ||||
const char *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) */ if (unlink(sfn) == -1) { /* Handle error */ } sfp = fdopen(fd, "w+"); if (sfp == NULL) { close(fd); /* Handle error */ } /* Use temporary file */ fclose(sfp); /* also closes fd */ |
...
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Compass/ROSE |
|
| Can detect violations of this recommendation. Specifically, Rose reports use of | ||||||
Coverity | 6.5 | SECURE_TEMP | Fully Implemented. | ||||||
| 489 S | Partially implemented. | |||||||
PRQA QA-C |
| warncall tmpnam, tmpfile, mktemp, tmpnam_s | Partially implemented |
...
CERT C++ Secure Coding Standard | FIO43-CPP. Do not create temporary files in shared directories |
CERT Oracle Secure Coding Standard for Java | FIO03-J. Remove temporary files before termination |
ISO/IEC TR 24731-1:2007 | Section 6.5.1.1, "The tmpfile_s Function,"Section 6.5.1.2, "The tmpnam_s Function"Section 6.5.2.1, "The fopen_s Function" |
ISO/IEC TR 24772:2013 | Path Traversal [EWR] |
MITRE CWE | CWE-379, Creation of temporary file in directory with insecure permissions |
Bibliography
...
[Austin Group 2008] | |
[HP 2003] | |
[Kennaway 2000] | |
[Open Group 2004] | mktemp() mkstemp() 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" |
...