The SELinux binprm hook function implementations manage the security
fields of linux_binprm
structures and perform
access control for program loading operations. This section
describes these hooks and their helper functions.
The selinux_bprm_alloc_security
and
selinux_bprm_free_security
hook functions
currently do nothing for SELinux. At present, the SELinux module
directly stores the new SID for the task in the security field of the
linux_binprm
structure, so a separate
security structure is not allocated. In order to support stacking
with other security modules that use the security field, the SELinux
module will need to be changed to allocate a separate security
structure and store the SID in this structure.
The selinux_bprm_alloc_security
hook function
calls the secondary security module to support the owlsm
RLIMIT_NPROC
check in this hook. However, since
any use of the security field by the secondary module would create a
conflict for the other SELinux binprm hooks, this hook also checks
whether the secondary module set the security field. If so, then the
secondary module is unregistered to prevent conflicts between SELinux
and the secondary module on subsequent binprm hook calls. Stacking
with such modules requires a common mechanism for chaining multiple
security objects on the security field, as mentioned in Section 8.
The selinux_bprm_set_security
hook function is
called while loading a new program to fill in the
linux_binprm
security field and optionally to
check permissions. This hook function may be called multiple times
during a single execve, e.g. for interpreted scripts. This hook
function first calls the secondary security module to support Linux
capabilities. If the security field has already been set by a prior
call, this hook merely returns. This allows security transitions
to occur on scripts if permitted by the policy.
By default, this hook function sets the security field to the SID of
the current task. This function checks the current task's security
structure to see if the task specified a new SID for the task. If so,
then this SID is used. Otherwise, the security server is consulted
using the security_transition_sid
interface to
see whether the SID should change based on the current SID of the task
and the SID of the program.
This hook function then performs different permission checks depending
on whether the SID of the task is changing. The permission checks for
each case are described below. The file execute
permission check is performed by the
selinux_inode_permission
hook, so it is not
listed here.
The file execute_no_trans
permission is checked
when a task would remain in the same SID upon executing a program, as
shown in Table 4. This permission check
ensures that a task is allowed to execute a given program without
changing its security attributes. For example, although the login
process can execute a user shell, it should always change its SID at
the same time, so it does not need this permission to the shell
program.
Table 4. Permission Checks if Task SID is not changing on exec
Source | Target | Permission(s) |
---|---|---|
Current | ProgramFile | execute_no_trans |
The process transition
permission and the file
entrypoint
permission are checked when the SID of
a task changes. The transition
permission check
ensures that the old SID is allowed to transition to the new SID. The
entrypoint
permission check ensures that the new
SID can only be entered by executing particular programs. Such
programs are referred to as entrypoint programs for the SID. These
permission checks are shown in Table 5.
The selinux_bprm_compute_creds
hook function is
called to set the new security attributes for the task. This hook
function first calls the secondary security module to support Linux
capabilities. This hook then copies the current SID of the task into
the old SID field of the task security structure to support the
getosecsid
system call. If the new SID is the
same as the old SID, then nothing further is done by this hook.
Two additional permission checks may occur when the SID of the task is
changing. If the task is being traced, then the
ptrace
permission is checked between the parent
task and the new SID. If the task was created via
clone
and has shared state, then the
share
permission is checked between the old and
new SIDs. If these permission checks fail, then the task SID is left
unchanged and the task is sent a SIGKILL to terminate it.
These permission checks are shown in Table 6.
Table 6. Permission Checks if Task SID is changing on exec
Source | Target | Permission(s) |
---|---|---|
ParentTask | NewTaskSID | ptrace |
Current | NewTaskSID | share |
If all permissions are granted, this hook function changes the SID of
the task to the new SID. It then calls the
flush_unauthorized_files
helper function to close
any file descriptors to which the task should no longer have access.
This helper function calls file_has_perm
on each
open file with requested permissions that correspond to the file mode
and flags, and closes the open file if these permissions are not
granted under the new SID. The file_has_perm
function is described in Section 15.2.1. Finally,
this hook function wakes up the parent task if it is waiting on this
task. This allows the selinux_task_wait
hook to
recheck whether the parent task is allowed to wait on the task under
its new SID and to handle a denial appropriately.