Versions Compared

Key

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

...

This is a dangerous practice 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 only be accessed only by application instances (making sure that multiple instances of the application running on the same platform do not compete).

...

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 these criteria:

...

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 only secure solution is to not to create temporary files in shared directories.

...

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

...

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

...

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
 
void func(void) {
  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 */
  }
}

...

Code Block
bgColor#FFCCCC
langc
#include <stdio.h>
 
void func(void) {
  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 */
  }
}

...

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

...

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 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 */
  }
}

...

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().) Section Subclause 7.21.4.4 of the C Standard [ISO/IEC 9899:2011] allows for the value of the macro TMP_MAX to be as small as 25.

...

The ISO/IEC TR 24731-1 function tmpfile_s() 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.

...

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.

...

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

FIO43-C

highHigh

probableProbable

mediumMedium

P12

L1

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 or SIGTSTP 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 could rm tmp2 and then symlink it to /etc or something. It would then rm /etc/ed.XXXXXX, but that probably wouldn't buy you much.

John McDonald

...

Tool

Version

Checker

Description

Compass/ROSE

 

 

Can detect violations of this recommendation. Specifically, Rose reports use of tmpnam(), tmpnam_s(), tmpfile(), and mktemp()

Coverity6.5SECURE_TEMPFully Implemented

LDRA tool suite

Include Page
LDRA_V
LDRA_V

489 S

Partially implemented

PRQA QA-C
Include Page
PRQA_V
PRQA_V
warncall tmpnam, tmpfile, mktemp, tmpnam_sPartially implemented

Related Vulnerabilities

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

...

CERT C++ Secure Coding StandardFIO43-CPP. Do not create temporary files in shared directories
CERT Oracle Secure Coding Standard for JavaFIO03-J. Remove temporary files before termination
ISO/IEC TR 24731-1:2007Subclause 6.5.1.1, "The tmpfile_s Function,"
Subclause 6.5.1.2, "The tmpnam_s Function"
Subclause 6.5.2.1, "The fopen_s Function"
ISO/IEC TR 24772:2013Path Traversal [EWR]
MITRE CWECWE-379, Creation of temporary file in directory with insecure permissions

...