Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

Programmers frequently create temporary files . Commonly, temporary file in directories that are writable by everyone (examples being are /tmp and /var/tmp on UNIX , and C:\TEMP %TEMP% on Windows) and may be purged regularly (for example, every night or during reboot).

When two or more users, or a group of users, have write permission to a directory, the potential for sharing and deception is far greater than it is for shared access to a few files. The vulnerabilities that result from malicious restructuring via hard and symbolic links suggest that it is best to avoid shared directories.

Securely creating temporary files in a shared directory is error prone and dependent on the version of the C runtime library used, the operating system, and the file system. Code that works for a locally mounted file system, for example, may be vulnerable when used with a remotely mounted file system.

Wiki Markup
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 03\]. Unprivileged programs can be similarly exploited to overwrite protected user files.

Consequently, certain rules need to be followed when using temporary files to mitigate or lessen the dangers associated with using them.

At a minimum, the following requirements must be met when creating temporary files:

...

Temporary files are commonly used for auxiliary storage for data that does not need to, or otherwise cannot, reside in memory and also as a means of communicating with other processes by transferring data through the file system. For example, one process will create a temporary file in a shared directory with a well-known name or a temporary name that is communicated to collaborating processes. The file then can be used to share information among these collaborating processes.

This practice is dangerous because a well-known file in a shared directory can be easily hijacked or manipulated by an attacker. Mitigation strategies include the following:

  1. Use other low-level IPC (interprocess communication) mechanisms such as sockets or shared memory.
  2. Use higher-level IPC mechanisms such as remote procedure calls.
  3. Use a secure directory or a jail that can be accessed only by application instances (ensuring that multiple instances of the application running on the same platform do not compete).

There are many different IPC mechanisms; some require the use of temporary files, and others do not. An example of an IPC mechanism that uses temporary files is the POSIX mmap() function. Berkeley Sockets, POSIX Local IPC Sockets, and System V Shared Memory do not require temporary files. Because the multiuser nature of shared directories poses an inherent security risk, the use of shared temporary files for IPC is discouraged.

When two or more users or a group of users have write permission to a directory, the potential for deception is far greater than it is for shared access to a few files. Consequently, temporary files in shared directories must be

  • 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 the above these criteria:

Conformance of File Functions to Criteria for Temporary Files
 


tmpnam
(

C99

C)

tmpnam_s
(

ISO/IEC TR 24731-1

Annex K)

tmpfile
(

C99

C/POSIX)

tmpfile_s
(

ISO/IEC TR 24731-1)

Annex K)

mktemp
(POSIX)

mkstemp
(POSIX)

Unpredictable

name

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 Access

Possible

Possible

No

If supported by OS

Possible

If supported by OS

Appropriate Permissions

Possible

Possible

No

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.

None Securely creating temporary files is error prone and dependent on the version of the C runtime library used, the operating system, and the file system. Code that works for a locally mounted file system, for example, may be vulnerable when used with a remotely mounted file system. Moreover, none of these functions are without problems. The best advice only secure solution is to not to create temporary files in shared directories. In cases where it is absolutely necessary to do so, however, the tmpfile_s() and mkstemp() provide the most secure solutions.

Unique and Unpredictable

...

File Names

Privileged programs Programs that create temporary files in shared world-writable directories may can be exploited to overwrite protected system files. For example, an 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, the a protected system file referenced by to which the symbolic link points can be overwritten when the program is executed . To ensure that the name of the temporary file does not conflict with a preexisting file and that it cannot be guessed before the program is run, temporary files must be created with unique and unpredictable file names[HP 2003]. Unprivileged programs can be similarly exploited to overwrite protected user files.

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 05|AA. C References#Seacord 05]\] Chapter 7).. (See Secure Coding in C and C++, Chapter 8[Seacord 2013].)

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

  • Shared locks, provided by LockFile(), prohibit all write access to the locked file region while allowing concurrent read access to all processes

...

  • .
  • Exclusive locks, provided by LockFileEx(), grant unrestricted file access to the locking process while denying access to all other processes.

In both cases, A call to LockFile() obtains shared access; exclusive access is accomplished via LockFileEx(). In either case the lock is removed by calling UnlockFile().

...

These Windows file-locking mechanisms are called mandatory locks because every process attempting to access to a locked file region is subject to the restriction. Linux implements both mandatory locks and advisory locks. An advisory lock is not enforced by the operating system, which severely diminishes its value from a security perspective. Unfortunately, the mandatory file lock in Linux is also largely impractical for the following reasons:

...

  • Mandatory locking works only on local file systems and does not extend to network file systems (such as NFS

...

  • or AFS).

...

  • File systems must be mounted with support for mandatory locking, and this is disabled by default.

...

  • Locking relies on the group ID bit that can be turned off by another process (thereby defeating the lock).

Removal before

...

Termination

Removing temporary files when they are no longer required allows file names It is important to remember to cleanup in order to allow filenames 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 tmp , temporary file cleaner utilities are widely used. These tmp cleaners are invoked manually by , which are invoked manually by a system administrator or periodically run as by a cron daemon to sweep temporary directories and remove old files. These tmp cleaners , are widely used. However, these utilities are themselves vulnerable to file-based exploits, and often require the use of shared directories (see: TMP00-A. Do not create temporary files in shared directories). However, during . During normal operation, it is the responsibility of the program to ensure that temporary files are removed either removed explicitly , or through the use of library routines, such as tmpfile_s, which guarantee their removal temporary file deletion upon program termination.

...

Noncompliant Code Example

...

(fopen()/open() with tmpnam()

...

)

This noncompliant code example The following non-compliant code creates a file with some a hard-coded file_name (presumably in a shared directory such as /tmp or C:\Temp).:

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
 
void func(const char *file_name[] = /* hard coded string */;
FILE *fp;

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

Since 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.

Wiki MarkupThe following non-compliant code attempts to remedy the problem by generating the filename at runtime using {{tmpnam()}}. The C99 {{tmpnam()}} function generates a string that is a valid filename and that is not the same as the name of an existing file \[[ISO/IEC 9899-1999|AA. C References#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 This noncompliant code example attempts to remedy the problem by generating the file name at runtime using tmpnam(). The C tmpnam() function generates a string that is a valid file name and that is not the same as the name of an existing file. 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. 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
#include <stdio.h>
 
void func(void) {
  char file_name[L_tmpnam];
  FILE * fp;

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

  /* A TOCTOU race condition exists here */

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

Since neither does Because tmpnam() does not guarantee a unique name , nor does and fopen() does not provide a facility for an exclusive open, this code is still vulnerable to the exploit above.unmigrated-wiki-markup

The next noncompliant code sample example attempts to remedy the problem by using {{open()}}, defined in the Open Group Base Specifications Issue 6 \[[Open Group 04|AA. C References#Open Group 04]\], and providing a mechanism to indicate whether an existing file has been opened for writing or a new file has been created. 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()}}.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 [IEEE Std 1003.1:2013]. 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
bgColor#FFCCCC
langc
#include <stdio.h>
 
void func(void) {
  char file_name[L_tmpnam];
  int fd;

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

  /* A TOCTOU race condition exists here */

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

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

Care should be observed when using {{O_EXCL}} with remote file systems , as 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 95|AA. C References#Callaghan 95]\], in particular the {{EXCLUSIVE}} value to the {{mode}} argument of {{CREATE}}.

Wiki Markup
Moreover, the {{open()}} function as specified by the Open Group Base Specifications Issue 6 \[[Open Group 04|AA. C References#Open Group 04]\] does not include support for shared or exclusive locks.

Callaghan 1995], particularly the EXCLUSIVE value to the mode argument of CREATE.

Moreover, the open() function, as specified by the Standard for Information Technology—Portable Operating System Interface (POSIX®), Base Specifications, Issue 7 [IEEE Std 1003.1:2013], does not include support for shared or exclusive locks. However, BSD systems support two additional flags that allow you to obtain a shared or exclusive lockthese locks:

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

...

Noncompliant Code Example

...

(tmpnam_s()

...

/open(), Annex K, POSIX)

The C Standard function 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. It is almost identical to the tmpnam() function except for an added maxsize argument for the supplied buffer.

Code Block
bgColor#FFCCCC
langc
#define __STDC_WANT_LIB_EXT1__
#include <stdio.h>
 
void func(void) {
  char file_name[L_tmpnam_s];
  int fd;

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

  /* A TOCTOU 

Wiki Markup
The TR 24731-1 {{tmpnam_s()}} function generates a string that is a valid filename 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.

Non-normative text in TR 24731-1 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, this reduces the space for unique names and increases the predictability of the resulting names. But in general, TR 24731-1 does not establish any criteria for the predictability of names.

Code Block
bgColor#FFCCCC

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 */
 
if((  fd = open(file_name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC,
            0600));
  if (fd < 0) {
    /* Handle Errorerror */
  }

Implementation Details

For Microsoft Visual Studio 2005, the name generated by tmpnam_s consists of a program-generated filename 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).

...

}

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 filename file name template and overwrites a portion of it to create a filenamefile name. The template may be any filename with some number of Xs file name with exactly six X's appended to it (for example, /tmp/temp.XXXXXX). The six trailing Xs X's are replaced with the current process number and/or a unique letter combination. The number of unique filenames mktemp() can return depends on the number of Xs provided.

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
#include <stdlib.h>
 
void func(void) {
  char file_name[] = "tmp-XXXXXX";
  int fd;

  if (!mktemp(file_name)) {
    /* Handle Errorerror */
  }

  /* A TOCTOU race condition exists here */

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

The mktemp() function has been is marked "LEGACY" in the Open Group Base Specifications Issue 6 [Open Group 2004]. The man manual page for mktemp() gives more detail:

Never use mktemp(). Some implementations follow BSD 4.3 and replace XXXXXX 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 of mktemp() is a security risk. The race is avoided by mkstemp(3).

...

Noncompliant Code Example

...

(tmpfile())

The C99 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 This limit may be shared with tmpfiletmpnam().) . The Subclause 7.21.4.4, paragraph 6, of the C Standard allows for the value of the macro TMP_MAX is only required to be 25 by the C99 standard to be as small as 25.

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

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
 
void func(void) {
  FILE * fpfp = tmpfile();

  if (!(fp == tmpfile(NULL))) {
    /* Handle Errorerror */
  }

Compliant Solution: mkstemp() (POSIX)

A reasonably secure solution for generating random file names is to use the mkstemp() function. The mkstemp() function is available on systems that support the Open Group Base Specifications Issue 4, Version 2 or later.

A call to mkstemp() replaces the six Xs in the template string with six randomly selected characters and returns a file descriptor for the file (opened for reading and writing):

Code Block

char template[] = "temp-XXXXXX";
if ((fd = mkstemp(template)) == -1) {
   /* Handle Error */
}

The mkstemp() algorithm for selecting filenames has proven to be immune to attacks.

Code Block
bgColor#ccccff

char sfn[] = "temp-XXXXXX";
FILE *sfp;
int fd;

if ((fd = mkstemp(sfn)) == -1) {
  /* Handle Error */
}

/* We unlink immediately to allow the name to be recycled */
/* The race condition here is inconsequential if the file was created with exclusive permissions (glibc >= 2.0.7) */

unlink(sfn);

if ((sfp = fdopen(fd, "w+")) == NULL) {
  close(fd);
  /* Handle Error */
}

/* use temporary file */

fclose(sfp); /* also closes fd */

Wiki Markup
The Open Group Base Specification Issue 6 \[[Open Group 04|AA. C References#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 (that is, POSIX.1-2008) specifies them as {{S_IRUSR\|S_IWUSR}} (0600).

Implementation Details

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 Markup
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 has recently changed the {{mk*temp()}} family to eliminate the PID component of the filename and replace the entire field with base-62 encoded randomness.  This raises the number of possible temporary files for the typical use of 6 Xs significantly, meaning that even {{mktemp()}} with 6 Xs is reasonably (probabilistically) secure against guessing, except under frequent usage \[[Kennaway 00|AA. C References#Kennaway 00]\] .

Compliant Solution: 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 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 (non-shared) 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 only required to be 25 by ISO/IEC TR 24731-1.

The tmpfile_s() function is available on systems that support ISO/IEC TR 24731-1.

TR 24731-1 notes the following regarding the use of tmpfile_s() instead of tmpnam_s():

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.

Code Block
bgColor#ccccff

if (tmpfile_s(&fp)) {
  /* Handle Error */
}

Risk Assessment

Failure to create unique, unpredictable temporary file names can make it possible for an attacker to access or modify privileged files.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

TMP30-C

3 (high)

2 (probable)

1 (high)

P6

L2

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Sections 7.19.4.4, "The {{tmpnam}} function," 7.19.4.3, "The {{tmpfile}} function," and 7.19.5.3, "The {{fopen}} function"
\[[ISO/IEC PDTR 24772|AA. C References#ISO/IEC PDTR 24772]\] "EWR Path Traversal"
\[[ISO/IEC TR 24731-1-2007|AA. C References#ISO/IEC TR 24731-1-2007]\] Sections 6.5.1.2, "The {{tmpnam_s}} function," 6.5.1.1, "The {{tmpfile_s}} function," and 6.5.2.1, "The {{fopen_s}} function"
\[[Open Group 04|AA. C References#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 05a|AA. C References#Seacord 05a]\] Chapter 3, "File I/O"
\[[Wheeler 03|AA. C References#Wheeler 03]\] [Chapter 7, "Structure Program Internals and Approach"|http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/avoid-race.html#TEMPORARY-FILES]
\[[Viega 03|AA. C References#Viega 03]\] Section 2.1, "Creating Files for Temporary Use"
\[[Kennaway 00|AA. C References#Kennaway 00]\]
\[[HP 03|AA. C References#HP 03]\]

}

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]:

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.

Code Block
bgColor#FFCCCC
langc
#define __STDC_WANT_LIB_EXT1__
#include <stdio.h>
 
void func(void) {
  FILE *fp;
 
  if (tmpfile_s(&fp)) {
    /* Handle error */
  }
}

The tmpfile_s() function should not be used with implementations that create temporary files in a 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 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.

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
bgColor#ccccff
langc
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
extern int secure_dir(const char *sdn);
 
void func(void) {
  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 */
}

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] does not specify the permissions the file is created with, so these are implementation-defined. However, IEEE Std 1003.1, 2013 Edition [IEEE Std 1003.1:2013] specifies them as S_IRUSR|S_IWUSR (0600).

This compliant solution invokes the user-defined function secure_dir() (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.

Implementation Details

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, 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].

Exceptions

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

Remediation Cost

Priority

Level

FIO21-C

Medium

Probable

Medium

P8

L2

 Automated Detection

Tool

Version

Checker

Description

CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

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 tmpnam(), tmpnam_s(), tmpfile(), and mktemp()

Coverity6.5SECURE_TEMPFully implemented
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

C5016
LDRA tool suite
Include Page
LDRA_V
LDRA_V

44 S

Enhanced enforcement

Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V
CERT_C-FIO21-a
Usage of functions prone to race is not allowed
Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rec. FIO21-CChecks for non-secure temporary file (rec. partially covered)


Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Bibliography

[HP 2003]
[IEEE Std 1003.1:2013]XSH, System Interfaces: open
XSH, 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]mkstemp()
mktemp()

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"


...

Image Added Image Added Image AddedTMP00-A. Do not create temporary files in shared directories      10. Temporary Files (TMP)       TMP32-C. Temporary files must be opened with exclusive access