Versions Compared

Key

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

...

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
bgColor#ccccff
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]\].

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
bgColor#ccccff

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.

Time of creation to time of use (TOCTOU) race condition vulnerabilities can be exploited to gain elevated privileges.

...