The Linux file system code was studied to determine the location to implement each permission check associated with the control requirements specified in the design. Several factors influenced the placement of permission checks. Whenever possible, the permission checks were implemented in the filesystem-independent code so that they are applied to all file system types. Only a few control requirements are specific to the ext2 file system type, so this was feasible for almost all of the permission checks. Permissions are typically checked as early as possible in the processing of each system call to simplify cleanup from permission failures and to ease maintenance of the checks as the file system code evolves. For services that are also controlled by a Linux access control check, the Flask permission check was usually implemented at the same location. However, a Flask permission cannot be checked until the kernel data structures for the necessary objects are accessible and appropriately locked. This required deferring some of the Flask permission checks until a later point in the processing.
To reduce the overhead of permission checks, the file system component was changed to store references to AVC entries with its file description (struct file) objects and inode (struct inode) objects. Two reference fields were added to the struct file: one for the permissions granted to the file description, and one for the permissions granted to the file. Since many of the file operations use pathname parameters rather than file descriptors, a field for storing a reference to the AVC entry containing the permissions granted to the file was also added to the struct inode.
Table 17 shows the control requirements implemented in each kernel function used to manipulate files. Only the class and permission are shown for each control requirement; the source SID and target SID can be found in the corresponding design table. The functions that implement the services for reading and writing files revalidate the permissions initially checked during open_namei, using the AVC entry reference in the file description. Since these permissions also migrate into the page cache for memory-mapped files, any cached pages from a file are invalidated when the SID of a file is changed. As a result, subsequent access to the pages will cause filemap_nopage to be executed. The inode_change_ok function implements both the permission checks for changing the SID of a file and the permission check for changing the ordinary Linux attributes of a file. Only the control requirements implemented in ext2_ioctl are specific to the filesystem type.
|
The control requirements implemented in each kernel function used to manipulate directories are shown in Table 18. The lookup_dentry function checks search permission on each directory in the path prefix. All of the system calls use this function to perform pathname lookup. The functions for changing the current and root directories must also perform a search permission check against the last component of the path. The may_create and may_delete functions provide convenient locations for the Flask control requirements on the containing directory. The unlink and rmdir permission checks had to be implemented separately from the may_delete function, since those checks should not be applied when the rename call removes the old link. The sys_getdents and old_readdir functions revalidate read permission using the AVC entry reference in the file description.
|
|
The remaining tables (Table 19 and Table 20) show the control requirements implemented in the kernel functions used to manipulate file systems and file descriptions. The mount and mountassociate permissions depend on the SID of the file system being mounted and the SID of the root directory of that file system. Consequently, these checks are deferred until after the file system metadata has been loaded, just prior to linking the file system into the file system name space.