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

Compare with Current View Page History

« Previous Version 31 Next »

The rename() function has the following prototype.

int rename(char const *old, char const *new);

If the file referenced by new exists prior to calling rename(), the behavior is implementation-defined. For portability, you must ensure that the file referenced by new does not exist when rename() is invoked.

Non-Compliant Code Example

In this non-compliant code example, a file is moved using rename().

char const *old = /* ... */;
char const *new = /* ... */;
if (rename(old, new) != 0) {
  /* Handle Error */
}

If the file named by new exists at the time of the call to rename(), the result is implementation-defined.

Compliant Solution

This compliant solution checks for the existence of the new file before callling rename(). This code contains an unavoidable race condition between the call to fopen() and the call to rename(). Consequently, this code can only be safely executed within a secure directory.

char const *old = /* ... */;
char const *new = /* ... */;
FILE *file = fopen(new, "r");

if (!file) {
  if (rename(old, new) != 0) {
    /* Handle Error */
  }
} else {
  fclose(file);
  /* handle Error */
}

Unfortunately, fopen() may fail on many file systems when the file exists but the program does not have sufficient permissions to read it.

Compliant Solution (POSIX)

A somewhat better solution involves using the POSIX access() function which can check for the existence of a file explicitly [[Open Group 04]].

char const *old = /* ... */;
char const *new = /* ... */;

if (access(new,F_OK) != 0) {
  if (rename(old, new) != 0) {
    /* Handle Error */
  }
} else {
  /* Handle Error */
}

While the likelihood of access() returning a false negative is lower than that of fopen(), on file systems where the program does not have sufficient permissions in the directory to view the file, access() may return -1 even when the file exists. In such cases, rename() will also likely fail since the program does not have adequate permissions inside the directory.

Compliant Solution (Windows)

On Windows, _access_s() allows one to check for the existence of a file [[MSDN]].

char const *old = /* ... */;
char const *new = /* ... */;

if (_access_s(new,0) != 0) {
  if (rename(old, new) != 0) {
    /* Handle Error */
  }
} else {
  /* Handle Error */
}

This _access_s() example shares many of the same problems as the POSIX access() example above.

Risk Assessment

Calling rename() 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-A

medium

probable

medium

P8

L2

Related Vulnerabilities

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

References

[[ISO/IEC 9899:1999]] Section 7.9.4.2, "The rename function"
[[MSDN]] _access_s, _waccess_s
[[Open Group 04]] access()


FIO09-A. Be careful with binary data when transferring data across systems      09. Input Output (FIO)       FIO11-A. Take care when specifying the mode parameter of fopen()

  • No labels