...
| Code Block | ||
|---|---|---|
| ||
char *filename = /* file name */;
char *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 Errorerror */
}
|
This code contains a time-of-creation-to-time-of-use (TOCTOU) race condition 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 FIO01-C. Be careful using functions that use file names for identification).
...
| Code Block | ||
|---|---|---|
| ||
char *filename = /* file name */;
char *userbuf = /* user data */;
unsigned int userlen = /* length 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.
...