...
If not properly performed, checking for the existence of symbolic links can lead to time of creation to time of use (TOCTOU) race conditions.
Non-Compliant Code Example (POSIX)
The only function available on POSIX systems to collect information about a symbolic link rather than its target is the lstat() function. This non-compliant code example uses the lstat() function to collect information about the file, checks the st_mode field to determine if the file is a symbolic link, and then opens the file if it is not a symbolic link.
| Code Block | ||
|---|---|---|
| ||
char *filename; struct stat lstat_info; int fd; /* ... */ if (lstat(filename, &lstat_info) == -1) { /* handle error */ } if (!S_ISLNK(lstat_info.st_mode)) { if ((fd = open(filename, O_EXCL|O_RDWR, 0600)) == -1) { /* handle error */ } } write(fd, userbuf, userlen); |
| Wiki Markup |
|---|
This code contains a time of creation to time of use (TOCTOU) race condition betwen the call to {{lstat()}} and the subsequent call to {{open()}} because both functions operate on a file name \[[FIO01-A|FIO01-A. Prefer functions that do not rely on file names for identification]\] that can be manipulated asynchronously to the execution of the program. |
Compliant Solution (POSIX)
This compliant solution eliminates the race condition by:
...
| Code Block | ||
|---|---|---|
| ||
char *filename; struct stat lstat_info, fstat_info; int fd; /* ... */ if (lstat(filename, &lstat_info) == -1) { /* handle error */ } if ((fd = open(filename, O_EXCL|O_RDWR, 0600)) == -1) { /* handle error */ } if (fstat(fd, &fstat_info) == -1) { /* handle error */ } if (lstat_info.st_mode == fstat_info.st_mode && lstat_info.st_ino == fstat_info.st_ino && lstat_info.st_dev == fstat_info.st_dev) { write(fd, userbuf, userlen); } |
| Wiki Markup |
|---|
Tihs eliminate the TOCTOU condition because {{fstat()}} is applied to file descriptors, not file names, so the file passed to {{fstat()}} must be identical to the file that was opened. The {{lstat()}} function does not follow symbolic links, but {{fstat()}} does. Comparing modes using the {{st_mode}} field is sufficient to check for a symbolic link.
Comparing i-nodes using the {{st_ino}} fields and devices using the {{st_dev}} fields ensures that the file passed to {{lstat()}} is the same as the file passed to {{fstat()}} \[[FIO05-A|FIO05-A. Identify files using multiple file attributes]\]. |
Risk Assessment
Time of creation to time of use (TOCTOU) race condition vulnerabilities can be exploited to gain elevated privileges.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
FI031 POS35-A C | 3 (high) | 3 (likely) | 2 (medium) | P18 | L1 |
Examples of vulnerabilities resulting from the violation of this rule can be found on the CERT website.
References
| Wiki Markup |
|---|
\[[Dowd 06|AA. C References#Dowd 06]\] Chapter 9, "UNIX 1: Privileges and Files" \[[ISO/IEC 9899-1999|AA. C References#ISO/IEC 9899-1999]\] Section 7.19, "Input/output <stdio.h>" \[[Open Group 04|AA. C References#Open Group 04]\] [lstat()|http://www.opengroup.org/onlinepubs/000095399/functions/lstat.html], [fstat()|http://www.opengroup.org/onlinepubs/009695399/functions/fstat.html], [open()|http://www.opengroup.org/onlinepubs/009695399/functions/open.html] \[[Seacord 05|AA. C References#Seacord 05]\] Chapter 7, "File I/O" |