15. File Hook Functions

The SELinux file hook functions manage the security fields of file structures and perform access control for file operations. Each file structure contains state such as the file offset and file flags for an open file. Since file descriptors may be inherited across execve calls and may be transferred through IPC, they can potentially be shared among processes with different security attributes, so it is desirable to separately label these structures and control the use of them. Additionally, it is necessary to save task security information in these structures for SIGIO signals.

15.1. Managing File Security Fields

15.1.1. File Security Structure

The file_security_struct structure contains security information for file objects. This structure is defined as follows:

struct file_security_struct {
        unsigned long magic;
        struct file *file;
        struct list_head list;
        security_id_t sid;
        security_id_t fown_sid;
        avc_entry_ref_t avcr;
        avc_entry_ref_t inode_avcr;
};

Table 20. file_security_struct

FieldDescription
magicModule id for the SELinux module.
file Back pointer to the associated file.
list Pointer used to maintain the list of allocated file security structures.
sidSID of the open file descriptor.
fown_sidSID of the file owner; used for SIGIO events.
avcrAVC entry reference for the file.
inode_avcrAVC entry reference for the associated inode.

15.1.2. file_alloc_security and file_free_security

The file_alloc_security and file_free_security helper functions are the primitive allocation functions for file security structures. In addition to the general security field management, file_alloc_security tries to associate the file with the SID of the current task. If the security structure of the current task is not already set, the file is associated with the unlabeled SID. Callers of this function should first call task_precondition on the current task if possible. The file_free_security simply releases all resources.

The selinux_file_alloc_security calls the task_precondition function to ensure that the SID of the current task is set and then calls the helper function. The selinux_file_free_security hook functions merely calls the helper function.

15.1.3. file_precondition

The file_precondition helper function ensures that the file security structure is allocated and initialized prior to use. This function calls task_precondition on the current task and then calls file_alloc_security.

15.1.4. selinux_file_set_fowner

This hook function is called to save security information about the current task in the file security structure for later use by the selinux_file_send_sigiotask hook. One example of where this hook is called is the fcntl call for the F_SETOWN command. This hook saves the SID of the current task in the fown_sid field of the file security structure.

15.2. Controlling File Operations

15.2.1. file_has_perm

This helper function checks whether a task can use an open file descriptor to access a file in a given way. It takes the task, the file, and the requested file permissions as parameters. This function first calls the AVC to check use permission between the task and the file descriptor. If this permission is granted, then this function also checks the requested permissions to the file using the dentry_has_perm helper function. In some cases (e.g. lseek), this helper function is called with no requested file permissions in order to simply check the ability to use the descriptor. In these cases, the latter check is omitted.

15.2.2. selinux_file_permission

This hook function is called by operations such as read, write, and sendfile to revalidate permissions on use to support privilege bracketing or policy changes. It takes the file and permission mask as parameters. If the O_APPEND flag is set in the file flags, then this hook function first sets the MAY_APPEND flag in permission mask. This function then converts the permission mask to an access vector using the file_mask_to_av function, and calls file_has_perm with the appropriate parameters.

15.2.3. selinux_file_llseek

This hook function is called by the lseek and llseek system calls to control access to the file offset. It calls file_has_perm with no requested file permissions to simply check access to the file descriptor.

15.2.4. selinux_file_ioctl

This hook function is called by the ioctl system call. It calls file_has_perm with a requested file permission based on the command argument. For some commands, no file permission is specified so only the use permission is checked. The generic ioctl file permission is used for commands that are not specifically handled. Table 21 shows the permission checks performed for each command.

Table 21. I/O Control Permission Checks

CommandSourceTargetPermission(s)

FIONREAD
FIBMAP
FIGETBSZ
EXT2_IOC_GETFLAGS
EXT2_IOC_GETVERSION

Current

FileDescriptor
File

use
getattr

EXT2_IOC_SETFLAGS
EXT2_IOC_SETVERSION

Current

FileDescriptor
File

use
setattr

FIONBIO
FIOASYNC

CurrentFileDescriptoruse
OtherCurrent

FileDescriptor
File

use
ioctl

15.2.5. selinux_file_mmap

This hook function is called by mmap to check permission when mapping a file. At present, if anonymous memory is being mapped, i.e. the file parameter is NULL, no checks are performed. However, this may be changed later to ensure that execute access to anonymous memory can be controlled. If a file is being mapped, then file_has_perm is called with a set of permissions based on the flags and protection parameters.

Since read access is always possible with file mapping, the read permission is always required. The write permission is only checked if the mapping is shared and PROT_WRITE was requested. The execute permission is only checked if PROT_EXEC was requested. However, on some architectures, read access to memory is sufficient to execute code from it, so the ability to strictly control code execution is limited on such architectures.

It should be noted that the protection on a mapping may subsequently become invalid due to a file relabel or a change in the security policy. Hence, support for efficiently locating and invalidating the appropriate mappings upon such changes is needed to support full revocation. This support has not yet been implemented for the SELinux security module.

15.2.6. selinux_file_mprotect

This hook function is called by the mprotect call to check the requested new protection for an existing mapping. This hook simply calls selinux_file_mmap with the file, new protection value, and the existing flags for the mapping.

15.2.7. selinux_file_lock

This hook function is called by the flock system call. It calls file_has_perm with the lock permission.

15.2.8. selinux_file_fcntl

This hook function is called by the fcntl system call. It calls file_has_perm with a requested file permission based on the command parameter. The basic permission checks performed for each command are shown in Table 22.

Table 22. File Control Permission Checks

CommandSourceTargetPermission(s)

F_SETFL
F_SETOWN
F_SETSIG
F_GETFL
F_GETOWN
F_GETSIG

CurrentFileDescriptoruse

F_GETLK
F_SETLK
F_SETLKW
F_GETLK64
F_SETLK64
F_SETLKW64

Current

FileDescriptor
File

use
lock

In addition to these basic checks, the write permission is checked if the F_SETFL command is used to clear the O_APPEND flag. This ensures that a process that only has append permission to the file cannot subsequently obtain full write access after opening the file.

15.2.9. selinux_file_send_sigiotask

This hook function is called to check whether a signal generated by an event on a file descriptor can be sent to a task. This function is always called from interrupt. It is passed the target task, a file owner structure and several other parameters that are unused by SELinux. Since the file owner structure is embedded in a file structure, the file structure and its security field can be extracted by the hook function. The hook function calls the AVC to check the appropriate signal permission between the fown_sid in the file security structure and the target task SID.

15.2.10. selinux_file_receive

This hook function is called to check whether the current task can receive an open file descriptor that was sent via socket IPC. This function calls the file_to_av function to convert the file flags and mode to an access vector and then calls file_has_perm to check that the receiving task has these permissions to the file. If this hook returns an error, then the kernel will cease processing the message and will pass a truncated message to the receiving task.