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.

Managing File Security Fields

File Security Structure

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

struct file_security_struct {
        struct file *file;
        u32 sid;
        u32 fown_sid;
};

Table 23. file_security_struct

FieldDescription
file Back pointer to the associated file.
sidSID of the open file descriptor.
fown_sidSID of the file owner; used for SIGIO events.

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 associates the open file with the SID of the allocating task. The selinux_file_alloc_security and selinux_file_free_security hook functions simply call the helper functions.

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.

Controlling File Operations

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 sets up the auxiliary audit data. It then 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 inode_has_perm helper function. In some cases (e.g. certain ioctl and fcntl commands), 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.

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 permission mask is null (an existence test), then the function returns success immediately. Otherwise, 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.

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 24 shows the permission checks performed for each command.

Table 24. 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

file_map_prot_check

This helper function is called by the selinux_file_mmap and the selinux_file_mprotect hook functions to apply permission checks for attempts to create or change the protection of memory mappings. The function first checks whether the caller is attempting to make executable an anonymous mapping or a private file mapping that will also be writable. If so, it applies the process execmem permission check to control the ability to execute arbitrary code from memory.

If a file is being mapped, then this function calls the file_has_perm with a set of permissions based on a flag indicating whether the mapping is shared and the requested protection. Since read access is always possible with a 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.

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.

selinux_file_mmap

This hook function is called to check permission when creating a mapping. The hook function determines whether the mapping will be shared based on the provided flags and calls the file_map_prot_check helper.

selinux_file_mprotect

This hook function is called to check the requested new protection for an existing mapping. If the caller is attempting to make the mapping executable, this function first applies several specialized checks. If the mapping is in the brk region, then the process execheap permission is checked to control attempts to make the heap executable, which should normally never occur and is not portable; such memory if needed should be explicitly allocated via mmap. If the mapping is a private file mapping that has had some copy-on-write done, indicating that it may include modified content, then this function performs a file execmod permission check. Typically, this should only occur for text relocations, which if possible should be eliminated from the program or DSO. If the mapping is in the main process stack, this function checks the process execstack permission to control attempts to make the stack executable; as with execheap, such memory if needed should be explicitly allocated via mmap. This function then determines whether the mapping is shared based on the flags in the vm_area_struct and calls the file_map_prot_check helper to complete checking. Note that in the execstack case, this will also trigger an execmem check, so both permissions would have to be allowed in order to permit making the stack executable; however, in practice, the more likely situation is that one would allow execmem to a particular program to permit legitimate runtime code generation while denying execstack to prevent making its stack executable.

selinux_file_lock

This hook function is called to check permissions before performing file locking operations. It calls file_has_perm with the lock permission.

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 25.

Table 25. 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.

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 sometimes called from interrupt. It is passed the target task, a file owner structure and the signal that would be delivered (or 0 if SIGIO is to be used as the default). 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.

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.

selinux_quota_on

This hook function is called to check permissions when quotas are enabled to a particular quota file. It calls file_has_perm to check quotaon permission to the file.