Versions Compared

Key

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

Many common operating systems, such as Windows and UNIX, support symbolic (soft) links. Symbolic links can be created in UNIX using the ln -s command or in Windows by using directory junctions in NTFS or the Linkd.exe (Win 2K resource kit) or "junction" freeware.

If not properly performed, checking for the existence of symbolic links can lead to time of creation to time of use (TOCTOU) race conditions.

...

race conditions.

This rule is a specific instance of rule FIO45-C. Avoid TOCTOU race conditions while accessing files.

The POSIX lstat() function collects information about a symbolic link rather than its target. This non-compliant noncompliant 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#FFCCCC
langc
char *filename = /* file name */;
char *filename;
userbuf = /* user data */;
unsigned int userlen = /* length of userbuf string */;

struct stat lstat_info;
int fd;
/* ... */
if (lstat(filename, &lstat_info) == -1) {
  /* handleHandle error */
}

if (!S_ISLNK(lstat_info.st_mode)) {
   fd = open(filename, O_RDWR);
   if (fd == -1) {
       /* handleHandle error */
   }
}
if (write(fd, userbuf, userlen); < userlen) {
  /* Handle error */
}

This code contains a time-of creation to -check, time-of-use (TOCTOU) race condition betwen between the call to lstat() and the subsequent call to open() because both functions operate on a file name that can be manipulated asynchronously to the execution of the program. (see See FIO01-AC. Be careful using functions that use file names for identification.)

This compliant solution eliminates the race condition by using O_NOFOLLOW to cause open() to fail if passed a symbolic link, avoiding the TOCTOU by not having a separate "check" and "use":

Code Block
bgColor#ccccff
langc
char *filename = /* file name */;
char *userbuf = /* user data */;
unsigned int userlen = /* length of userbuf string */;

int fd = open(filename, O_RDWR|O_NOFOLLOW);
if (fd == -1) {
  /* Handle error */
}
if (write(fd, userbuf, userlen) < userlen) {
  /* Handle error */
}

This compliant solution eliminates the race condition by:

  1. calling Calling lstat() on the file name.
  2. calling Calling open() to open the file.
  3. calling Calling fstat() on the file descriptor returned by open().
  4. comparing Comparing the file information returned by the calls to lstat() and fstat() to ensure that the files are the same.
Code Block
bgColor#ccccff
langc
char *filename = /* file name */;
char *userbuf = /* user data */;
unsigned int userlen = /* length *filename;of userbuf string */;

struct stat lstat_info;
struct stat fstat_info;
int fd;
/* ... */
if (lstat(filename, &lstat_info) == -1) {
  /* handle error */
}

fd = open(filename, O_RDWR);
if (fd == -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) {
  if (write(fd, userbuf, userlen); < userlen) {
    /* Handle Error */
  }
}

This code 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(). (see See FIO05-AC. Identify files using multiple file attributes.).

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

Rule

Severity

Likelihood

Remediation Cost

Detectable

Repairable

Priority

Level

POS35-C

High

Likely

No

No

P9

L2

Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V
user_definedSoundly supported
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-POS35
Compass/ROSE



Can detect some violations of this rule. In particular, it ensures that calls to open() that are preceded by a call to lstat() are also followed by a call to fstat().

Coverity
Include Page
Coverity_V
Coverity_V

TOCTOU

Implemented
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

DF4886, DF4887, DF4888


Klocwork
Include Page
Klocwork_V
Klocwork_V

SV.TOCTOU.FILE_ACCESS
CERT.STR.ASSIGN.CONST_TO_NONCONST


Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C

high

likely

medium

P18

L1

-POS35-b

Avoid race conditions while checking for the existence of a symbolic link

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule POS35-C

Checks for file access between time of check and use (TOCTOU) (rule fully covered)

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

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>"
\[[MITRE 07|AA. C References#MITRE 07]\] [CWE ID 365|http://cwe.mitre.org/data/definitions/365.html], "Race Condition in Switch"
\[[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"

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CWE 2.11CWE-363, Race condition enabling link following2017-07-07: CERT: Exact

Key here for mapping notes

Independent( CWE-764, POS51-C, POS35-C)

CWE-764 is about semaphores, or objects capable of being locked multiple times. Deadlock arises from multiple locks being acquired in a cyclic order, and generally does not arise from semaphores or recursive mutexes.

[Dowd 2006]Chapter 9, "UNIX 1: Privileges and Files"
[ISO/IEC 9899:2024]Section 7.23, "Input/output <stdio.h>"
[Open Group 2004]lstat()
fstat()
open()
[Seacord 2013]Chapter 8, "File I/O"


...

Image Added Image Added Image Removed      50. POSIX (POS)       Image Modified