Versions Compared

Key

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

...

File identification is less of an issue if applications maintain their files in secure directories, where they can only be accessed by the owner of the file and (possibly) by a system administrator. (See recommedation FIO15-C. Ensure that file operations are performed in a secure directory.)

...

Code Block
bgColor#FFCCCC
langc

char *file_name;

/* initialize file_name */

FILE *fd = fopen(file_name, "w");
if (fd == NULL) {
  /* Handle error */
}

/*... write to file ...*/

fclose(fd);
fd = NULL;

/*
 * A race condition here allows for an attacker to switch 
 * out the file for another 
 */

/* ... */

fd = fopen(file_name, "r");
if (fd == NULL) {
  /* Handle error */
}

/*... read from file ...*/

fclose(fd);
fd = NULL;

...

Code Block
bgColor#ccccff
langc

struct stat orig_st;
struct stat new_st;
char *file_name;

/* initialize file_name */

int fd = open(file_name, O_WRONLY);
if (fd == -1) {
  /* Handle error */
}

/*... write to file ...*/

if (fstat(fd, &orig_st) == -1) {
  /* Handle error */
}
close(fd);
fd = -1;

/* ... */

fd = open(file_name, O_RDONLY);
if (fd == -1) {
  /* Handle error */
}

if (fstat(fd, &new_st) == -1) {
  /* Handle error */
}

if ((orig_st.st_dev != new_st.st_dev) ||
    (orig_st.st_ino != new_st.st_ino)) {
  /* file was tampered with! */
}

/*... read from file ...*/

close(fd);
fd = -1;

This enables the program to recognize if an attacker has switched files between the first close() and the second open(). The program does not recognize if recognize whether the file has been modified in - place, however.

Alternatively, the same solution can be implemented using the C99 C fopen() function to open the file and the POSIX fileno() function to convert the FILE object pointer to a file descriptor.

The structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atime, st_ctime, and st_mtime should all have meaningful values for all file types on POSIX-compliant systems. The st_ino field contains the file serial number. The st_dev field identifies the device containing the file. The st_ino and st_dev, taken together, uniquely identify the file. The st_dev value is not necessarily consistent across reboots or system crashes; , however, so you may not be able to use this field for file identification if there is a possibility of a system crash or reboot before you attempt to reopen a file.

Call the fstat() function on a file that is already opened instead of calling stat() on a file name followed by open(). This ensures that the file for which the information is being collected is the same file that is already opened. See recommendation FIO01-C. Be careful using functions that use file names for identification for more information on avoiding race conditions resulting from the use of file names for identification.

It may also be necessary to call open() with O_NONBLOCK, as per rule FIO32-C. Do not perform operations on devices that are only appropriate for files, to ensure that the program does not hang when trying to open special files.

This compliant solution may not work in some cases. For instance, a long-running service might choose to occasionally reopen a log file to add log messages , but leave the file closed, so that the log file may be periodically rotated. In this case, the inode i-node number would change, and this solution would no longer apply.

Compliant Solution (POSIX) (

...

Open Only Once)

A simpler solution is to not reopen the file. In this code example, the file is opened once for both writing and reading. Once writing is complete, the fseek() function resets the file pointer to the beginning of the file, and its contents are read back. (See recommendation FIO07-C. Prefer fseek() to rewind().)

...

Code Block
bgColor#ccccff
langc

char *file_name;
FILE *fd;

/* initialize file_name */

fd = fopen(file_name, "w+");
if (fd == NULL) {
  /* Handle error */
}

/*... write to file ...*/

/* go to beginning of file */
fseek(fd, 0, SEEK_SET);

/*... read from file ...*/

fclose(fd);
fd = NULL;

Be sure to use fflush() after writing data to the file, in accordance with rule FIO39-C. Do not alternately input and output from a stream without an intervening flush or positioning call.

...

Code Block
bgColor#FFCCCC
langc

char *file_name;
FILE *fd;

/* initialize file_name */

fd = fopen(file_name, "r+");
if (fd == NULL) {
  /* Handle error */
}

/* read user's file */

fclose(fd);
fd = NULL; 

...

Code Block
bgColor#ccccff
langc

struct stat st;
char *file_name;

/* initialize file_name */

int fd = open(file_name, O_RDONLY);
if (fd == -1) {
  /* Handle error */
}

if ((fstat(fd, &st) == -1) ||
   (st.st_uid != getuid()) ||
   (st.st_gid != getgid())) {
  /* file does not belong to user */
}

/*... read from file ...*/

close(fd);
fd = -1;

...

Alternatively, the same solution can be implemented using the C99 C fopen() function to open the file and the POSIX fileno() function to convert the FILE object pointer to a file descriptor.

...

Compass/ROSE

could

Could report possible violations of this rule merely by reporting any open() or fopen() call that did not have a subsequent call to fstat().

Tool

Version

Checker

Description

Section

 

 

Section

Related Vulnerabilities

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

...

CERT C++ Secure Coding Standard: FIO05-CPP. Identify files using multiple file attributes

ISO/IEC 9899:1999 Section 2011 Section 7.1921.3, "Files," and Section 7.1921.4, "Operations on Filesfiles"

ISO/IEC TR 24772 "EWR Path Traversaltraversal"

MITRE CWE: CWE-37, "Path Issue issue - Slash Absolute Pathabsolute path"

MITRE CWE: CWE-38, "Path Issue - Backslash Absolute Pathabsolute path"

MITRE CWE: CWE-39, "Path Issue - Drive Letter letter or Windows Volumevolume"

MITRE CWE: CWE-62, "UNIX Hard Linkhard link"

MITRE CWE: CWE-64, "Windows Shortcut Following shortcut following (.LNK)"

MITRE CWE: CWE-65, "Windows Hard Linkhard link"

Bibliography

[Drepper 2006] Section 2.2.1 "Identification When Openingwhen opening"
[Open Group 2004] "The open function," and "The fstat function"
[Seacord 2005] Chapter 7, "File I/O"

...