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.
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; }; |
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.
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.
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.
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.
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
Command | Source | Target | Permission(s) | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
| Current |
|
| |||||||||
| Current |
|
| |||||||||
| Current | FileDescriptor | use | |||||||||
Other | Current |
|
|
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.
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.
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.
This hook function is called to check permissions before performing file
locking operations. It calls file_has_perm
with the
lock
permission.
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
Command | Source | Target | Permission(s) | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Current | FileDescriptor | use | ||||||||||
| Current |
|
|
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.
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.
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.
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.