Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Cut out info covered by POS35

...

In rare cases, it is necessary to check for the existence of symbolic or hard links to ensure that a program is reading from an intended file and not a different file in another directory. In these cases, avoid creating a race condition when checking for the existence of symbolic links.

Also, see POS35-C. Avoid race conditions while checking for the existence of a symbolic link

...

If the process is running with elevated privileges, an attacker can exploit this code, for example, by creating a link from .conf to the /etc/passwd authentication file. The attacker can then overwrite data stored in the password file to create a new root account with no password. As a result, this attack can be used to gain root privileges on a vulnerable system.

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, and then checks the st_mode field to determine if the file is a symbolic link.

Code Block
bgColor#FFCCCC

struct stat lstat_info;
int fd;
if (lstat("some_file", &lstat_info) == -1) {
  /* handle error */
}
if (!S_ISLNK(lstat_info.st_mode)) {
   if ((fd = open("some_file", O_RDWR)) == -1) {
       /* handle error */
   }
}
write(fd, userbuf, userlen);

Unfortunately, this code is vulnerable to a TOCTOU race condition. An attacker can exploit this vulnerability by creating a link named "some_file" to an arbitrary file after the lstat() function but before the open() function.

...

Code Block
bgColor#ccccff
int fd;
if ((fd = open("some_file", O_RDWR | O_NOFOLLOW)) == -1) {
  /* handle error */
}
write(fd, userbuf, userlen);

This compliant solution properly checks for the existence of a link and eliminates the race condition.

Code Block
bgColor#CCCCff

struct stat lstat_info, fstat_info;
int fd;
if (lstat("some_file", &lstat_info) == -1) {
  /* handle error */
}
if ((fd = open("some_file", 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);
}

...

Failing to check for the existence of links can result in a critical system file being overwritten, leading to a data integrity violation.

...