...
| Wiki Markup |
|---|
When available (Linux 2.1.26+, FreeBSD, Solaris 10, POSIX.1-2008), the {{O_NOFOLLOW}} should also be used, see \[[POS01-A. Check for the existence of links]\]. When {{O_NOFOLLOW}} is not available, symbolic link checks should use the method from \[[POS35-C. Avoid race conditions while checking for the existence of a symbolic link]\]. |
| Code Block | ||
|---|---|---|
| ||
#ifdef O_NOFOLLOW
#define OPEN_FLAGS O_NOFOLLOW | O_NONBLOCK
#else
#define OPEN_FLAGS O_NONBLOCK
#endif
/* ... */
struct stat orig_st;
struct stat open_st;
int fildes;
int flags;
if (!fgets(filename, sizeof(filename), stdin)) {
/* handle error */
}
if ((statlstat(file_name, &orig_st) != 0) || (!S_ISREG(orig_st.st_mode))) {
/* handle error */
}
/* A TOCTOU exists here, see note */
if ((fildes = open(filename, OPEN_FLAGS | O_WRONLY)) == -1) {
/* handle error */
}
if (fstat(fildes, &open_st) != 0) {
/* handle error */
}
if ((orig_st.st_mode != open_st.st_mode) ||
(orig_st.st_ino != open_st.st_ino) ||
(orig_st.st_dev != open_st.st_dev)) {
/* file was tampered with */
}
/* Optional: drop the O_NONBLOCK now that we are sure this is a good file */
if ((flags = fcntl(fildes, F_GETFL)) == -1) {
/* handle error */
}
if ((fcntl(fildes, F_SETFL, flags & ~O_NONBLOCK) != 0) {
/* handle error */
}
/* operate on file */
|
Regarding the inevitable TOCTOU vulnerability between the statlstat() check and open() call, there are essentially four cases that could result from an attacker switching out the file for one of the following:
Type | Note on effect | ||
|---|---|---|---|
another regular file | The | ||
FIFO | Either | ||
symbolic link | | ||
special device | Usually the | special device | Most systems require superuser privileges to tamper with devices, at which point there is little that can be done on |
Keep in mind that this TOCTOU is not a problem if the program can guarantee a safe environment for itself by properly managing permissions and ensuring that an attacker cannot have write or modify access to files.
...