You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 40 Next »

Privileged programs that create files in world-writable directories can 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, the protected system file referenced by the symbolic link can be overwritten when the program is executed. Therefore, 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 filenames.

Non-Compliant Code Example: fopen()

The following non-compliant code creates some_file in the /tmp directory. The name is hard-coded and is thus not unique or unpredictable.

FILE *fp = fopen("/tmp/some_file", "w");

If /tmp/some_file already exists, then that file is opened and truncated. If /tmp/some_file is a symbolic link, then the target file referenced by the link is truncated.

To exploit this coding error, an attacker need only create a symbolic link called /tmp/some_file before execution of this statement.

Non-Compliant Code Example: open()

The fopen() function does not indicate whether an existing file has been opened for writing or a new file has been created. However, the open() function as defined in the Open Group Base Specifications Issue 6 [[Open Group 04]] provides such a mechanism. 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().

int fd = open("/tmp/some_file", O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0600);

This call to open() fails whenever /tmp/some_file already exists, including when it is a symbolic link. This is a good thing, but a temporary file is presumably still required. One approach that can be used with open() is to generate random filenames and attempt to open() each until a unique name is discovered. Luckily, there are predefined functions that perform this function.

Care should be observed when using O_EXCL with remote file systems, as 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]], in particular the EXCLUSIVE value to the mode argument of CREATE.

Non-Compliant Code Example: 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]]. 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. If the argument is not a null pointer, it is assumed to point to an array of at least L_tmpnam chars; the tmpnam() function writes its result in that array and returns the argument as its value.

/* ... */
if (tmpnam(temp_file_name)) {
  /* temp_file_name may refer to an existing file */
  t_file = fopen(temp_file_name,"wb+");
  if (!t_file) {
     /* Handle Error */
  }
}
/* ... */

Non-Compliant Code Example: tmpnam_s() (ISO/IEC TR 24731-1)

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]]. The function is potentially capable of generating TMP_MAX_S different strings, but any or all of them may already be in use by existing files and thus not be suitable return values. The lengths of these strings must be less than the value of the L_tmpnam_s macro.

The L_tmpnam_s macro expands to an integer constant expression that is the size needed for an array of char large enough to hold a temporary filename string generated by the tmpnam_s() function. The TMP_MAX_S macro expands to an integer constant expression that is the maximum number of unique filenames that can be generated by the tmpnam_s() function. The value of the macro TMP_MAX_S is only required to be 25 by ISO/IEC TR 24731-1.

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.

TR 24731-1 does not establish any criteria for predictability of names.

/* ... */
FILE *file_ptr;
char filename[L_tmpnam_s];

if (tmpnam_s(filename, L_tmpnam_s) != 0) {
  /* Handle Error */
}

if (!fopen_s(&file_ptr, filename, "wb+")) {
  /* Handle Error */
}
/* ... */

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

Non-Compliant Code Example: mktemp()/open() (POSIX)

The POSIX function mktemp() takes a given filename template and overwrites a portion of it to create a filename. The template may be any filename with some number of Xs appended to it (for example, /tmp/temp.XXXXXX). The trailing Xs 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.

/* ... */
int fd;
char temp_name[] = "/tmp/temp-XXXXXX";

if (mktemp(temp_name) == NULL) {
  /* Handle Error */
}
if ((fd = open(temp_name, O_WRONLY | O_CREAT | O_EXCL | O_TRUNC, 0600)) == -1) {
  /* Handle Error */
}
/* ... */

The mktemp() function was marked LEGACY in the Open Group Base Specifications Issue 6.

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

It should be possible to open at least TMP_MAX temporary files during the lifetime of the program (this limit may be shared with tmpfile()). The value of the macro TMP_MAX is only required to be 25 by the C99 standard.

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

/* ... */
FILE *tempfile = tmpfile(void);
if (tempfile == NULL) {
  /* handle error condition */
}
/* ... */

The tmpfile() function may not be compliant with [[TMP33-C. Temporary files must be removed before the program exits]] for implementations where the temporary file is not removed if the program terminates abnormally.

Unable to render {include} The included page could not be found.
Unable to render {include} The included page could not be found.

Risk Assessment

A protected system file to which the symbolic link points can be overwritten when a vulnerable program is executed.

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

[[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 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]] mktemp(), mkstemp(), open()
[[Seacord 05a]] Chapter 3, "File I/O"
[[Wheeler 03]] Chapter 7, "Structure Program Internals and Approach"
[[Viega 03]] Section 2.1, "Creating Files for Temporary Use"
[[Kennaway 00]]
[[HP 03]]


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

  • No labels