Versions Compared

Key

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

The rename() function has the following prototype:

Code Block

int rename(const char *src_file, const char *dest_file);

If the file referenced by dest_file exists prior to calling rename(), the behavior is implementation-defined. On POSIX systems, the destination file is removed. On Windows systems, the rename() fails. This creates Consequently, issues arise when trying to write portable code or when trying to implement alternative behavior.

...

This code example is noncompliant because any existing destination file is removed by rename().:

Code Block
bgColor#ffcccc
langc

const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (rename(src_file, dest_file) != 0) {
  /* Handle Errorerror */
}

Compliant Solution (POSIX)

Wiki MarkupIf the programmer's intent is to not remove an existing destination not to remove an existing destination file, the POSIX {{access()}} function can be used to check for the existence of a file \[[Open Group 2004|AA. Bibliography#Open Group 04]\]. This compliant solution renames the source file only if the destination file does not exist.[IEEE Std 1003.1:2013]. This compliant solution renames the source file only if the destination file does not exist:

Code Block
bgColor#ccccff
langc

const char *src_file = /* ... */;
const char *dest_file = /* ... */;

if (access(dest_file, F_OK) != 0) {
  if (rename(src_file, dest_file) != 0) {
    /* Handle error condition */
  }
} 
else {
  /* Handle file-exists condition */
}

This code contains an unavoidable race condition between the call to access() and the call to rename() and can consequently be safely executed only when the destination file is located within a secure directory. (See recommendation FIO15-C. Ensure that file operations are performed in a secure directory.)

...

In situations where the source file is supposed not to be a directory or symbolic link, an alternative solution is to use link() to link the source file to the destination file and then use unlink() (or remove()) to delete the source file. Since Because link() fails if the destination file exists, this avoids the need for calling access() is avoided. However, this solution has two race conditions related to the source file. First, before calling link(), the program must use lstat() to check that the source file is not a directory or symbolic link. Second, there is  the source file could change during the time window between the link() and the unlink() during which the source file could change. Consequently, this alternative solution can be safely executed only when the source file is located within a secure directory.

Compliant Solution (Windows)

Wiki MarkupOn Windows, the [{{rename()}}|http://msdn.microsoft.com/en-us/library/zw5t957f(VS.80).aspx] function fails if \[[MSDN|AA. Bibliography#MSDN]\]if a

file File or directory specified by newname already exists or could not be created (invalid path). [MSDN]

Consequently, it is unnecessary to explicitly check for the existence of the destination file before calling rename().

Code Block
bgColor#ccccff
langc

const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (rename(src_file, dest_file) != 0) {
  /* Handle Errorerror */
}

Remove Existing Destination File

...

If the intent of the programmer is to remove the file referenced by dest_file if it exists prior to calling rename(), this code example is noncompliant on Windows platforms because rename() will fail.:

Code Block
bgColor#ffcccc
langc

const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (rename(src_file, dest_file) != 0) {
  /* Handle error */
}

...

On Windows systems, it is necessary to explicitly remove the destination file before calling rename(), if you want the programmer wants the file to be overwritten and the rename() operation to succeed.:

Code Block
bgColor#ccccff
langc

const char *src_file = /* ... */;
const char *dest_file = /* ... */;

if (_access_s(dest_file, 0) == 0) {
  if (remove(dest_file) != 0) {
    /* Handle error condition */
  }
}

if (rename(src_file, dest_file) != 0) {
  /* Handle error condition */
}

This code contains unavoidable race conditions between the calls to _access_s(), remove(), and rename() and can consequently be safely executed only within a secure directory. (See recommendation FIO15-C. Ensure that file operations are performed in a secure directory.)  Another option would be to use the MoveFileEx API and pass in the MOVEFILE_REPLACE_EXISTING flag:

Code Block
bgColor#ccccff
langc
const char *src_file = /* ... */;
const char *dest_file = /* ... */;

if (!MoveFileEx(src_file, dest_file, MOVEFILE_REPLACE_EXISTING)) {
  /* Handle error condition */
}

Although this code is not portable, it does avoid the race condition when using _access_s(), remove(), and rename().

Compliant Solution (POSIX)

On POSIX systems, if the destination file exists prior to calling rename(), the file is automatically removed.:

Code Block
bgColor#ccccff
langc

const char *src_file = /* ... */;
const char *dest_file = /* ... */;
if (rename(src_file, dest_file) != 0) {
  /* Handle error condition */
}

...

A programmer who wants an application to behave the same on any C99 C implementation must first determine what behavior to implement.

...

This compliant solution ensures that any destination file is portably removed.:

Code Block
bgColor#ccccff
langc

const char *src_file = /* ... */;
const char *dest_file = /* ... */;

(void)remove(dest_file);

if (rename(src_file, dest_file) != 0) {
  /* Handle error condition */
}

This code contains an unavoidable race condition between the call to remove() and the call to rename() and , consequently , can be safely executed only within a secure directory. (See recommendation FIO15-C. Ensure that file operations are performed in a secure directory.)

The return value of remove() is deliberately not checked because it is expected to fail in fail if the case where the file does not exist. If the file exists but cannot be removed, the rename() call will also fail, and the error will be detected at that point. This is a valid exception (EXP12-C-EX1) to recommendation EXP12-C. Do not ignore values returned by functions.

...

This compliant solution renames the source file only if the destination file does not exist.:

Code Block
bgColor#ccccff
langc

const char *src_file = /* ... */;
const char *dest_file = /* ... */;

if (!file_exists(dest_file)) {
  if (rename(src_file, dest_file) != 0) {
    /* Handle error condition */
  }
} 
else {
  /* Handle file-exists condition */
}

This code contains an unavoidable race condition between the call to file_exists() and the call to rename() and can consequently be safely executed only within a secure directory. (See recommendation FIO15-C. Ensure that file operations are performed in a secure directory.)

The file_exists() function is provided by the application and is not shown here because it must be implemented differently on different platforms. (On POSIX systems, it would use access(), ; on Windows, _access_s(), ; and on other platforms, whatever function is available to test file existence.)

Risk Assessment

Calling rename() has has implementation-defined behavior when the new file name refers to an existing file. Incorrect use of rename() can result in a file being unexpectedly overwritten or other unexpected behavior.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

FIO10-C

medium Medium

probable Probable

medium Medium

P8

L2

Automated Detection

Tool

Version

Checker

Description

CodeSonar
Include Page
CodeSonar_V
CodeSonar_V
(customization)Users can add a custom check for all uses of rename().
LDRA tool suite
Include Page
LDRA_V
LDRA_V
592 SFully Implemented
PRQA QA-C
Include Page
PRQA QA-C_v
PRQA QA-C_v
5015Partially implemented

Related Vulnerabilities

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

Related Guidelines

...

...

ISO/IEC 9899:1999 Section 7.9.4.2, "The rename function"

Bibliography

...

[IEEE Std 1003.1:2013]XSH, System Interfaces, access
[MSDN]rename()

 

...

Image Added Image Added Image Added

 

\[[MSDN|AA. Bibliography#MSDN]\] [{{rename()}}|http://msdn.microsoft.com/en-us/library/zw5t957f(VS.80).aspx]
\[[Open Group 2004|AA. Bibliography#Open Group 04]\] [{{access()}}|http://www.opengroup.org/onlinepubs/009695399/functions/access.html]
Image Removed      09. Input Output (FIO)      Image Removed