...
| Code Block | ||
|---|---|---|
| ||
FILE *fd = = fopen(file_name, "w"); if (fd == NULL) { /* Handle Error */ } /* Write to file */ fclose(fd); fd = NULL; /* * A race condition here allows for an attacker to switch * out the file for another */ /* ... */ fd = fopen(file_name, "r"); if (fd == NULL) { /* Handle Error */ } /* Read from file */ fclose(fd); fd = NULL; |
...
| Code Block | ||
|---|---|---|
| ||
struct stat orig_st;
struct stat new_st;
int fd = = open(file_name, O_WRONLY);
if (fd == -1) {
/* Handle Error */
}
/* Write to file */
if (fstat(fd, &orig_st) == -1)) {
/* Handle Error */
}
close(fd);
fd = -1;
/* ... */
fd = open(file_name, O_RDONLY);
if (fd == -1) {
/* Handle Error */
}
if (fstat(fd, &new_st) == -1)) {
/* Handle Error */
}
if ((orig_st.st_dev != new_st.st_dev) ||
(orig_st.st_ino != new_st.st_ino)) {
/* File was tampered with! */
}
/* Read from file */
close(fd);
fd = -1;
|
...
Non-Compliant Code Example (owner)
This In this non-compliant code example opens , the programmer's intent is to open a file for reading, relying , but only if the user running the process owns the specified file. This is a different, and generally more restrictive, requirement that that imposed by the operating system, which only requires that the user have permissions to read the file. The code, however, relies solely on the file name to identify the file. If this code runs with elevated privileges, for example, as part of a setuid-root program, it can be easily exploited.
| Code Block | ||
|---|---|---|
| ||
FILE *fd = fopen(file_name, "r");
if (fd == NULL) {
/* Handle Error */
}
/* Read user's file */
fclose(fd);
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 If this code is run with superuser privileges as part of a setuid-root program, an attacker could exploit this program to read a file files for which they lack sufficient privilgesthe user normally lacks sufficient privileges, including files not owned by the user.
Compliant Solution (POSIX) (owner)
In this compliant solution, the file is opened using the open() function. If the file is successfully opened, the fstat() function is used to read information about the file into the stat structure. This information is compared with existing information about the real user (obtained by the getuid() and getgid() functions.)
| Code Block | ||
|---|---|---|
| ||
struct stat st; int fd = -1; /* open file for reading */ ifint ((fd = open(file_name, O_RDONLY)); if (fd == -1) { /* Handle Error */ } if ((fstat(fd, &st) == -1) | (st.st_uid != getuid()) || (st.st_gid != getgid())) { /* File does not belong to user */ } /*... Read from file ...*/ close(fd); 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 user id and group idprogram now successfully restricts access to files owned by the real user of the program, by matching the file owner's user and group IDs to the processes real user and group IDs.
Alternatively, the same solution could be implemented using the C99 fopen() function to open the file and the POSIX fileno() function to convert the FILE object pointer to a file descriptor.
...