Versions Compared

Key

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

...

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

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

Because the name is hard coded and consequently neither unique nor unpredictable, an attacker need only replace a file with a symbolic link, and the target file referenced by the link is opened and truncated.

...

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

Because tmpnam() does not guarantee a unique name and fopen() does not provide a facility for an exclusive open, this code is still vulnerable.

...

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

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

...

Code Block
bgColor#FFCCCC
langc
char#define file__name[LSTDC_tmpnam_sWANT_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 */
  }
}

Nonnormative text in TR 24731-1 [ISO/IEC TR 24731-1:2007] also recommends the following:

...

Code Block
bgColor#FFCCCC
langc
char #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 has been marked "LEGACY" in the Open Group Base Specifications Issue 6 [Open Group 2004]. The manual page for mktemp() gives more detail:

...

Code Block
bgColor#FFCCCC
langc
FILE* fp = tmpfile(#include <stdio.h>
 
void func(void) {
  FILE *fp = tmpfile();
  if (fp == NULL) {
    /* Handle error */
  }
}

Noncompliant Code Example (tmpfile_s(), ISO/IEC TR 24731-1)

...

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

...

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); /* alsoAlso 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.

...

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:2007Section 6Subclause 6.5.1.1, "The tmpfile_s Function,"
Section 6Subclause 6.5.1.2, "The tmpnam_s Function"
Section 6Subclause 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

...

[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"

 

...