...
Non-Compliant Code Example
The only function available on POSIX systems to collect POSIX lstat() function collects 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, struct stat fstat_info; int fd; /* ... */ if (lstat(filename, &lstat_info) == -1) { /* handle error */ } if ((fd = open(filename, O_RDWR)) == -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 |
|---|
This eliminates 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 {{open()}} 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. Identify files using multiple file attributes]\]. |
Compliant Solution (POSIX.1-2008)
| Wiki Markup |
|---|
POSIX.1-2008 \[[Austin Group 08|AA. C References#Austin Group 08]\] adds an {{fstatat()}} function. The {{fstatat()}} is similar to the {{fstat()}} function, but provides an {{AT_SYMLINK_NOFOLLOW}} flag. The {{AT_SYMLINK_NOFOLLOW}} flag instructs {{fstatat()}} to return the status of the symbolic link instead of following it, if one is specified. |
| Code Block | ||
|---|---|---|
| ||
char *filename;
struct stat fstatat_info;
int fd;
/* ... */
if (fstatat(fd, filename, &fstatat_info, AT_SYMLINK_NOFOLLOW) == -1) {
/* handle error */
}
if (!S_ISLNK(fstatat_info.st_mode)) {
if ((fd = open(filename, O_RDWR)) == -1) {
/* handle error */
}
}
write(fd, userbuf, userlen);
|
It is important in this example that filename specifies an absolute path. If path specifies a relative path, the status is retrieved from a file relative to the directory associated with the file descriptor fd.
Risk Assessment
Time of creation to time of use (TOCTOU) race condition vulnerabilities can be exploited to gain elevated privileges.
...