...
| Code Block |
|---|
/dev/mouse /dev/console /dev/tty0 /dev/zero |
A web Web browser that failed to check for these devices would allow an attacker to create a website Web site with image tags such as <IMG src="file:///dev/mouse"> that would lock the user's mouse.
Noncompliant Code Example
In this noncompliant code example, the user can specify a locked device or a FIFO file name, causing the program to hang on the call to fopen().
| Code Block | ||
|---|---|---|
| ||
char *file_name;
FILE *file;
/* initialize file_name */
if (!fgets(file_name, sizeof(file_name), stdin)) {
/* handleHandle error */
}
if ((file = fopen(file_name, "wb")) == NULL) {
/* handleHandle error */
}
/* operate on file */
fclose(file);
|
...
When opening a FIFO with
O_RDONLYorO_WRONLYset:
- If
O_NONBLOCKis set, anopen()for reading only will return returns without delay. Anopen()for writing only will return returns an error if no process currently has the file open for reading.- If
O_NONBLOCKis clear, anopen()for reading only will block blocks the calling thread until a thread opens the file for writing. Anopen()for writing only will block blocks the calling thread until a thread opens the file for reading.When opening a block special or character special file that supports non-blocking opens:
- If
O_NONBLOCKis set, theopen()function will return returns without blocking for the device to be ready or available. Subsequent behaviour of the device is device-specific.- If
O_NONBLOCKis clear, theopen()function will block blocks the calling thread until the device is ready or available before returning.Otherwise, the behavior of
O_NONBLOCKis unspecified.
Once the file is open, programmers can use the POSIX lstat() and fstat() functions to obtain information about a named file , and the S_ISREG() macro to determine if the file is a regular file (see FIO05-C. Identify files using multiple file attributes).
...
| 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 fd;
int flags;
char *file_name;
/* initialize file_name */
if (!fgets(file_name, sizeof(file_name), stdin)) {
/* handleHandle error */
}
if ((lstat(file_name, &orig_st) != 0)
|| (!S_ISREG(orig_st.st_mode)))
{
/* handleHandle error */
}
/* A TOCTOU race condition exists here, see below */
fd = open(file_name, OPEN_FLAGS | O_WRONLY);
if (fd == -1) {
/* handleHandle error */
}
if (fstat(fd, &open_st) != 0) {
/* handleHandle 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(fd, F_GETFL)) == -1) {
/* handleHandle error */
}
if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) != 0) {
/* handleHandle error */
}
/* operateOperate on file */
close(fd);
|
The above code does contain an intractable TOCTOU race condition ; where under which an attacker can alter the file referenced by file_name following the call to lstat() but before the call to open(). The switch will be discovered after the file is opened, but opening the file cannot be prevented in the case where this action itself causes undesired behavior.
Essentially, an attacker can switch out a file for one of the file types shown in the table with the specified effect.
Table - File types and effect
Type | Note on effect |
|---|---|
another regular file | The |
FIFO | Either |
symbolic link |
|
special device | Usually the |
...
| Code Block | ||
|---|---|---|
| ||
HANDLE hFile = CreateFile(
pFullPathName, 0, 0, NULL, OPEN_EXISTING, 0, NULL
);
if (hFile == INVALID_HANDLE_VALUE) {
/* handleHandle error */
}
else {
if (GetFileType(hFile) != FILE_TYPE_DISK) {
/* handleHandle error */
}
/* operate on file */
}
|
...