12. Program Loading Hook Functions

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.

12.1. Managing Binprm Security Fields

12.1.1. selinux_bprm_alloc_security and selinux_bprm_free_security

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.

12.1.2. selinux_bprm_set_security

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

SourceTargetPermission(s)
CurrentProgramFileexecute_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.

Table 5. Permission Checks if Task SID is changing on exec

SourceTargetPermission(s)
CurrentNewTaskSIDtransition
NewTaskSIDProgramFileentrypoint

12.1.3. selinux_bprm_compute_creds

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

SourceTargetPermission(s)
ParentTaskNewTaskSIDptrace
CurrentNewTaskSIDshare

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.