Many file-related security vulnerabilities result from a program accessing a file object different from the one intended. In C99 [[ISO/IEC 9899-1999]], C character-based file names are bound to underlying file objects in name only. File names provide no information regarding the nature of the file object itself. Furthermore, the binding of a file name to a file object is reasserted every time the file name is used in an operation. File descriptors and FILE
pointers are bound to underlying file objects by the operating system. See [FIO03-A. Do not make assumptions about fopen() and file creation].
Accessing files via file descriptors or FILE
pointers rather than file names provides a greater level of certainty with regard to the object that is actually acted on. It is recommended that files be accessed through file descriptors or FILE
pointers where possible.
The following C99 functions rely solely on file names for file identification:
remove()
rename()
fopen()
freopen()
Use these functions with caution.
Non-Compliant Code Example
In this non-compliant code example, the file identified by file_name
is opened, processed, closed, and removed. However, it is possible that the file object identified by file_name
in the call to remove()
is not the same file object identified by file_name
in the call to fopen()
.
FILE * f_ptr = NULL; if ((f_ptr = fopen(file_name, "w")) == NULL) { /* Handle Error */ } /* Process file */ if (fclose(f_ptr) != 0) { /* Handle Error */ } if (remove(file_name) != 0) { /* Handle Error */ }
Compliant Solution
There is not much that can be programmatically done to ensure the file removed is the same file that was opened, processed, and closed except to make sure that the file is opened in a secure directory with privileges that would prevent the file from being manipulated by an untrusted user.
Non-Compliant Code Example (POSIX)
In this non-compliant code example, the function chmod()
is called to set the permissions of a file. However, it is not clear whether the file object referred to by file_name
refers to the same object in the call to fopen()
and in the call to chmod()
.
FILE * f_ptr = NULL;; if ((f_ptr = fopen(file_name,"w")) == NULL) { /* Handle Error */ } /* ... */ if (chmod(file_name, new_mode) == -1) { /* Handle Error */ } /* ... */
Compliant Solution (POSIX)
This compliant solution uses variants of the functions used in the non-compliant code example that operate on file descriptors or file pointers rather than file names. This guarantees that the file opened is the same file that is operated on.
int fd = -1; if ((fd = open(file_name, O_WRONLY | O_CREAT | O_EXCL, file_mode)) == -1) { /* Handle Error */ } /* ... */ if (fchmod(fd, new_mode) == -1) { /* Handle Error */ } /* ... */
The fchmod()
function is defined in IEEE Std 1003.1, 2004 [[Open Group 04]] and can only be used on POSIX-compliant systems.
Mitigation Strategies (POSIX)
Many file-related race conditions can be eliminated by using
fchown()
rather thanchown()
fstat()
rather thanstat()
fchmod()
rather thanchmod()
POSIX functions that have no file descriptor counterpart should be used with caution:
link()
andunlink()
mkdir()
andrmdir()
mount()
andunmount()
lstat()
mknod()
symlink()
utime()
Risk Assessment
Many file-related vulnerabilities, for instance Time of Check, Time of Use race conditions, are exploited to cause a program to access an unintended file. Using FILE pointers or file descriptors to identify files instead of file names reduces the chance of accessing an unintended file. Remediation costs can be high, because there is no portably secure solution.
Recommendation |
Severity |
Likelihood |
Remediation Cost |
Priority |
Level |
---|---|---|---|---|---|
FIO01-A |
2 (medium) |
2 (probable) |
1 (high) |
P4 |
L3 |
Automated Detection
The LDRA tool suite V 7.6.0 is able to detect violations of this recommendation.
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
References
[Apple Secure Coding Guide] "Avoiding Race Conditions and Insecure File Operations"
[[Drepper 06]] Section 2.2.1 "Identification When Opening"
[[ISO/IEC 9899-1999]] Section 7.19.3, "Files"
[[ISO/IEC 9899-1999]] Section 7.19.4, "Operations on Files"
[[Open Group 04]] "The open function"
[[Seacord 05]] Chapter 7, "File I/O"
FIO00-A. Take care when creating format strings 09. Input Output (FIO) FIO02-A. Canonicalize path names originating from untrusted sources