Check out the new USENIX Web site. next up previous
Next: Category 2: Controlled Objects Up: Type Error Categorization Previous: Type Error Categorization

Category 1: Inconsistent Checking and Usage of Controlled Object Variables

In this category, the variable that is checked is not the variable that is used subsequently. There is, however, some sort of mapping between the checked variable and the used variable (e.g. the used variable is a field of the checked variable). Therefore, it is easy to obtain the checked variable from the passed variable and vice versa.

These type errors are subject to TOCTTOU [2] attacks, because the mapping between the checked variable and the used variable might change during the course of execution. Whether the vulnerability is exploitable depends on whether the user can manipulate the mapping without special privilege. At least one of the type errors that we found is exploitable, as we demonstrate below.

Figure 8: Code path from Linux 2.4.9 containing an exploitable type error.
\begin{verbatim}/* from fs/fcntl.c */
long sys_fcn...{verbatim}/* operate on filp */

Figure 8 shows the code path that contains the type error. The code sequence shows Linux implementation of file locking via the fcntl system call. In function sys_fcntl() , the variable filp , which is a pointer to the file structure and is retrieved via the file descriptor fd , is checked by the security_ops->file_ops->fcntl(filp, ...) hook. However, after the check, the file descriptor fd , instead of the checked variable filp , is passed to the intermediate function do_fcntl(fd, ...) and eventually to the worker function fcntl_getlk(fd, ...) , where the filp is retrieved again with the given fd .

This double retrieval of the file pointer creates a race condition and can be exploited as follows. A user can have the security_ops->file_ops->fcntl(filp) authorization performed on a different file to the one that is eventually locked. Figure 9 shows the exploit.

Figure 9: An example exploit.
(1) fd1 = open(''myfile'...
(8) filp = fget (fd1)
(9) lock file\end{verbatim}\end{small}\end{figure}

Note that although step (7) is written as a whole system call, there is actually only one line of C (an assignment) in step (7) that needs to come between (6) and (8). Since step (6) does a get_user, the attacker can cause their own program to page fault which enables step (7) to be performed before (8).

Also note that non-LSM Linux is not vulnerable since the validation in fcntl_setlk is done after the second lookup. LSM is vulnerable because the only authorization that protects the operation is performed before the second lookup.

As an example of how dangerous this can be, login and su (PAM'd versions) both try to lock the file /var/run/utmp (world readable). insmod locks any modules it loads.

A patch that fixes this problem was posted to the LSM mailing list [5].

The remaining type errors in this category involve kernel data structures that cannot be easily modified by users via system calls. As a result, it is unclear whether these type errors can lead to exploits. However, it certainly complicates the code unnecessarily and increases the chance of race conditions when the data structures are not properly synchronized, which may result in potential exploits.

Here we present a type error of this kind. Many security checks that intend to protect the inode structure are performed on the dentry data structure. For example, the following code does the permission check on the dentry structure, but does the ``set attribute'' operation on the inode structure.

/* from fs/attr.c */
  ->setattr(dentry, attr);
inode = dentry->d_inode;
inode_setattr(inode, attr);

It is also quite common in Linux to check on the file data structure and operate on the inode data structure.

next up previous
Next: Category 2: Controlled Objects Up: Type Error Categorization Previous: Type Error Categorization
Catherine Zhang 2002-05-13