...
Consequently, temporary files in shared directories must be:
- created with unique and unpredictable file names,
- opened with exclusive access,
- removed before the program exits, and
- opened with appropriate permissions.
The following table lists common temporary file functions and their respective conformance to the above this criteria:
Conformance of file functions to criteria for temporary files
...
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. 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.
Noncompliant Code Example
...
(fopen()/open()
with tmpnam()
)
This noncompliant code example creates a file with a hard-coded file_name
(presumably in a shared directory such as /tmp
or C:\Temp
).
...
Because the name is hard coded and consequently neither unique nor unpredictable, an attacker need only place replace a file with a symbolic link in lieu of the file, and the target file referenced by the link is opened and truncated.
...
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 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 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
).
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 some number of X's appended to it (for example, /tmp/temp.XXXXXX
). The trailing X's 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 X's provided.
...
Never use
mktemp()
. Some implementations follow BSD 4.3 and replaceXXXXXX
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 ofmktemp()
is a security risk. The race is avoided bymkstemp(3)
.
Noncompliant 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 | ||
---|---|---|
| ||
FILE* fp = tmpfile(); if (fp == NULL) { /* Handle error */ } |
Noncompliant 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.
...
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.
Compliant Solution
...
(mkstemp()
...
, POSIX)
The mkstemp()
algorithm for selecting file names has proven shown to be immune to attacks. The mkstemp()
function is available on systems that support the Open Group Base Specifications Issue 4, Version 2 or later.
...
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 */ } /* useUse temporary file */ fclose(sfp); /* also closes fd */ |
...
This compliant solution invokes the an implementation-specific secure_dir(
} function (such as the one defined in FIO15-C. Ensure that file operations are performed in a secure directory) to ensure the temporary file resides in a secure directory.
...
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FIO43-C | high | probable | medium | P12 | L1 |
Question: Is the race condition caused by calling
unlink()
to hide the temporary file name less of a concern than the risk of not callingunlink()
?The
unlink()
function doesn't follow symlinks, and doesn't really have much of an affect on hard links. So, I guess your options for attacking something like that would be:
*SIGSTOP
orSIGTSTP
it before the unlink, maybe unlink it yourself and wait (a while) until something created something with the same name, or try to use that name somehow. Probably not that useful, but maybe in a specific attack it could work with a lot of effort.
*You could sorta do a symlink attack with an intermediate path component, for example, if it was/tmp/tmp2/ed.XXXXXX
, you couldrm tmp2
and then symlink it to/etc
or something. It would thenrm /etc/ed.XXXXXX
, but that probably wouldn't buy you much.John McDonald
Automated Detection
...