...
| Code Block | ||
|---|---|---|
| ||
FILE *fd = NULL; if ((fd = fopen(file_name, "w"); if (fd) == NULL) { /* Handle Error */ } /* writeWrite to file */ fclose(fd); } else { fd = NULL; /* handleA errorrace condition here */ } allows for an attacker to switch out the file for another */ /* reopen file_name ... */ if ((fd = fopen(file_name, "r"); if (fd) == NULL) { /* readHandle fromError file */ fclose(fd); } else { /* handleRead errorfrom conditionfile */ }fclose(fd); fd = NULL; |
There is no guarantee that the file opened for reading is the same file that was opened for writing. An attacker could substitute a malicious file between the first fclose() and the second fopen().
...
| Code Block | ||
|---|---|---|
| ||
struct stat orig_st; dev_t dev; /* device */ ino_t ino; /* file serial number */ int struct stat new_st; int fd = -1; if((fd = open(file_name, O_WRONLY)); if ((fd ! == -1) && { /* Handle Error */ } /* Write to file */ if (fstat(fd, &orig_st) !== -1)) { ino = st.st_ino; dev = st.st_dev; /* writeHandle to fileError */ } close(fd); } else { /* handle error condition */ } /* reopen previously written file */ fd = -1; /* ... */ if((fd = open(file_name, O_RDONLY); if ((fd !) == -1) &&{ /* Handle Error */ } if (fstat(fd, &new_st) !== -1)) &&{ /* Handle Error */ } if ((orig_st.st_inodev !== ino) && new_st.st_dev) || (orig_st.st_devino !== dev) new_st.st_ino)) { /* File readwas fromtampered filewith! */ close(fd); } else { /* handleRead errorfrom conditionfile */ }close(fd); fd = -1; |
This enables the program to recognize if an attacker has switched files on the program in between the first close() and the second open(). The program does not recognize if the file has been modified in-place, however.
...
| Wiki Markup |
|---|
It is necessary to call the {{fstat()}} function on an already opened file, rather than calling {{stat()}} on a file name followed by {{open()}} to ensure the file for which the information is being collected is the same file that is opened. See \[[FIO01-A. Be careful using functions that use file names for identification]\] for more information on avoiding race conditions resulting from the use of file names for identification. |
| Wiki Markup |
|---|
It may also be necessary to call {{open()}} with {{O_NONBLOCK}} as per \[[FIO32-C. Do not perform operations on devices that are only appropriate for files]\] to ensure that the program does not hang when trying to open special files. |
Non-Compliant Code Example (owner)
...
| Code Block | ||
|---|---|---|
| ||
FILE *fd = NULL; if ((fd = fopen(file_name, "r"); if (fd)) == NULL) { /* Handle Error */ } /* readRead user's file */ fclose(fd); } else { /* handle error condition */ }fd = NULL; |
There is no guarantee that the file opened is the correct file. In fact, the file opened may not even be owned by the user invoking the program. An attacker could use this program to access data they would normally not be privileged to read.
...
| Code Block | ||
|---|---|---|
| ||
struct stat st; uid_tint uidfd = getuid()-1; gid_t gid = getgid(); /* open file for reading */ if((fd = open(file_name, O_RDONLY)); if ((fd ! == -1) &&{ /* Handle Error */ } if((fstat(fd, &st) !== -1) &&| (st.st_uid !== uidgetuid()) &&|| (st.st_gid !== gid) ) { /* readgetgid())) { /* File does not belong to user */ } /* Read from file */ close(fd); } else { /* handle error condition */ }fd = -1; |
This enables the program to recognize if an attacker is passing data they don't control, by ensuring that the file's owner and group matchers the real userid and group id.
...