Task Hook Functions

The SELinux task hook function implementations manage the security fields of task_struct structures and perform access control for task operations. This section describes these hooks and their helper functions.

Managing Task Security Fields

Task Security Structure

The task_security_struct structure contains security information for tasks. This structure is defined as follows:

struct task_security_struct {
        struct task_struct *task;
        u32 osid;
        u32 sid;
        u32 exec_sid;
        u32 create_sid;
        u32 ptrace_sid;
};

Table 1. task_security_struct

FieldDescription
taskBack pointer to the associated task_struct structure.
osidSID prior to the last execve.
sidcurrent SID for the task.
exec_sidSID for the task upon the next execve call.
create_sidSID for files created by the task.

task_alloc_security and task_free_security

The task_alloc_security and task_free_security helper functions are the primitive allocation functions for task security structures. The selinux_task_alloc_security hook function calls task_alloc_security for the new task and then copies the SID fields from the current task into the new task. The selinux_task_free_security hook function simply calls the corresponding helper function.

selinux_task_reparent_to_init

This hook function is called by the kernel reparent_to_init function to set the security attributes for a kernel task. This hook function first calls the secondary security module to support Linux capabilities. It then sets the SID of the task to the kernel initial SID.

selinux_task_post_setuid

This hook function is called after a setuid operation has successfully completed. Since the SELinux module does not use the Linux identity attributes, this hook function does not perform any SELinux processing. However, it does call the secondary security module to support Linux capabilities.

selinux_task_to_inode

This hook function is called by the procfs pseudo filesystem to set the security state for the /proc/pid inodes associated with a task. This function sets the inode SID from the task SID and marks the inode security structure as initialized.

selinux_getprocattr

This hook function is called by the procfs pseudo filesystem to get a process security attribute value from the security module upon an attempt to read a node under the /proc/pid/attr directory. The hook function begins by checking getattr permission if the target task differs from the current task. It then extracts the appropriate SID from the task security structure. If the corresponding SID has not been set (e.g. if no explicit exec SID has been set and the task is using the default policy behavior), then the hook returns a zero length. Otherwise, the hook function calls security_sid_to_context to obtain the security context associated with the SID, copies the context to the provided kernel buffer (if it is large enough), and returns its length.

selinux_setprocattr

This hook function is called by the procfs pseudo filesystem to set a process security attribute value from the security module upon an attempt to write a node under the /proc/pid/attr directory. The hook function begins by checking whether the target task differs from the current task, returning an error in that case to prevent setting of a task's security attributes by another task. The function then applies a permission check between the current task and the target task (always a self relationship due to the prior restriction) based on the particular attribute being set. If a context was written to the node (as opposed to writing a zero length buffer to reset an exec or fscreate SID to the default policy behavior), then the function calls security_context_to_sid to convert it to a SID.

If the attribute is the exec or fscreate context, then the function proceeds to set the corresponding SID in the task security structure. For these attributes, further permission checks based on the specified security context are not performed until the execve or file creation operation occurs, at which point that operation may fail due to a lack of permission. This is partly a legacy of the original API, where extended system calls specified the SID for the operation as part of the operation call rather than separately setting a process attribute in advance. While it would be possible to duplicate some of this checking within the selinux_setprocattr hook function (e.g. process transition permission check), the hook function lacks the full context of the execve or file creation operation, e.g. the entrypoint program for execve and the parent directory, filesystem, and specific file type for file creation.

If the attribute is the current context (i.e. a dynamic context transition), then the hook function verifies that there are no other threads in the process, checks dyntransition permission between the old and new task SIDs, and if the process is being traced, checks ptrace permission between the tracer SID and the new SID. If all checks pass, then the task SID is set to the new value.

Controlling Task Operations

Helper Functions for Checking Task Permissions

Several helper functions are provided for performing task permission checks. These functions and their permission checks are summarized in Table 2. The task_has_perm function checks whether a task has a particular permission to another task. The task_has_capability function checks whether a task has permission to use a particular Linux capability. The task_has_system function checks whether a task has one of the permissions in the system security class. This security class is used for permissions that control system operations when there is no existing capability check or the capability check is too coarse-grained. The task_has_security function checks whether a task has permission to use one of the selinuxfs APIs.

Table 2. Task Helper Function Permission Checks

FunctionSourceTargetPermission(s)
task_has_permSourceTaskTargetTaskProcessPermission
task_has_capabilityTaskTaskCapabilityPermission
task_has_systemTaskKernelSystemPermission
task_has_securityTaskSecuritySecurityPermission

Except for task_has_perm, these permission checks are simply based on a single task, so the target SID is unnecessary. In the case of task_has_capability, the task's SID is passed for both the source and target SIDs. For task_has_system and task_has_security, a distinct initial SID is used for the target SID.

Hook Functions for Controlling Task Operations

The task hook functions that perform access control and their permission checks are summarized in Table 3. These functions call the task_has_perm helper function.

Table 3. Task Hook Function Permission Checks

HookSourceTargetPermission(s)
selinux_task_createCurrentCurrentfork
selinux_task_setpgidCurrentTargetTasksetpgid
selinux_task_getpgidCurrentTargetTaskgetpgid
selinux_task_getsidCurrentTargetTaskgetsession
selinux_task_getschedulerCurrentTargetTaskgetsched

selinux_task_setscheduler
selinux_task_setnice

CurrentTargetTasksetsched
selinux_task_killCurrentTargetTask

signull
sigchld
sigkill
sigstop
signal

selinux_task_waitChildTaskCurrent

sigchld
sigkill
sigstop
signal

selinux_task_setrlimitCurrentCurrentsetrlimit
selinux_ptraceParentChildptrace

Only three of these hook functions require further explanation. The selinux_task_kill hook function checks a permission between the current task and the target task based on the signal being sent. The selinux_task_wait checks a permission between the child task and the current task based on the exit signal set for the child task. This allows control over the ability of a process to reap a child process of a different SID. In both hooks, the SIGKILL and SIGSTOP signals have their own distinct permissions because neither of these two signals can be blocked. The SIGCHLD signal has its own distinct permission because it is commonly sent from child processes to parent processes. The signull permission is checked if a 0 signal is passed to kill, as this merely represents an existence test, not an actual signal delivery. For all other signals, the generic signal permission is used.

The selinux_task_rlimit hook checks setrlimit permission if a hard limit is being changed so that the hard limit can later be used as a safe reset point for the soft limit upon context transitions. See the section on selinux_bprm_apply_creds for further discussion of the resource limit inheritance control.

In addition to checking ptrace permission, the selinux_ptrace hook also sets the tracer SID in the child task's security structure for later use by selinux_bprm_apply_creds and selinux_setprocattr. See the Section called selinux_bprm_apply_creds and the Section called selinux_setprocattr for further discussion.

Several of the task hook functions for controlling operations are not used by the SELinux security module. These hook functions are:

  • selinux_task_setuid

  • selinux_task_setgid

  • selinux_task_setgroups

  • selinux_task_prctl

Since SELinux does not depend on the Linux identity attributes, and since these operations can only affect the current process, SELinux does not need to control these operations. Privileged aspects of these operations are already controlled via the selinux_capable hook function. However, it may be desirable in the future to add SELinux permissions to control these operations, e.g. to confine Linux identity changes at finer granularity.