SELinux/Tutorials/How does a process get into a certain context

How does a process get into a certain context
In the previous tutorials, we already got across the context in which a process resides, and which can be checked using utilities like ps -Z.

But how do processes get into this context?

Context inheritance
First of all, know that SELinux supports inheritance of contexts. Furthermore more, inheritance of contexts is the default behavior: if there is no policy in SELinux that specifies otherwise, then anything created will inherit the context of its parent.
 * A process running with context foo_t spawning another process (forking) will cause creation of a new process with foo_t context (as long as SELinux has no rules specifying otherwise)
 * A file or directory created in a directory with context bar_t will get the bar_t context as well (as long as SELinux has no rules specifying otherwise)

So, even if there is a context definition saying that should be auditd_log_t, if you create this  directory within  then this directory will inherit the var_log_t context from its parent directory. Only later, when you run restorecon, will the context be changed. This is because the creation of the file is what's known as a "Domain Transition" event, and those are handled dedicates rules, and not by any context mapping which exists for the file (like those we created with semanage in the previous tutorial).

Since we are talking about inheritance, there probably is a root context for everything. Well, there is - of course this is defined by the policy and SELinux support, but it is safe to assume that the root context (domain) for processes is the kernel_t context (as this is the context that the kernel runs as, and it is the kernel that spawns init, which itself spawns various other processes) and the root context for the file system is root_t.

Transitioning
Of course, SELinux would be quite dull if it didn't support switching to other contexts. And in this tutorial we want to talk about process context (domain) transitions: the idea that a process, once created, is within a different context than its parent process.

SELinux supports domain transitions when a process forks (spawns another process). And when you execute something, we mean that a process referred to some file (most likely a binary or a script) saying "execute this", so that the referred file is loaded and 'becomes' a process.

What an SELinux policy writer can do in these cases is to define a domain transition, like so:

type_transition init_t initrc_exec_t : process initrc_t;

Which reads:

When an init_t process executes a file with context initrc_exec_t, then the resulting process should run in the initrc_t context.

Or, in some ASCII-art flow:

[init_t] --(execute initrc_exec_t)--> [initrc_t]

Basically what the SELinux policy writer wants to achieve is that, when the init process (running on the Linux system) executes an init script (to be found in or ) then this script will run in the initrc_t domain.

Such a statement defines a default transition (that overrides the 'inherit parent context' rule - it can be used for file/directory contexts as well), but one can also use tools like runcon or SELinux API directly to achieve a non-default domain transition as long as it is allowed (read on).

The need for the file context
In the previous examples, you notice that the file context of the target file (to be executed) is used. Remember the previous tutorials on file contexts? SELinux does not use paths internally - it always uses contexts. So a policy writer cannot use, but has to refer to the context that this file would have - initrc_exec_t.

The syntax used is again a naming convention, but is not mandatory. SELinux also doesn't parse the name; the context could very well be called garble_mumble_joy. Naming conventions though are interesting since they allow us mere humans to understand what the purpose is of the context. So in case of initrc_exec_t, we could read this as "the context for an executable file that, when executed, might have the resulting process run in initrc_t".

Real-life example: startup of SSH
Let's look at a real-life example: the start-up of the SSH daemon.

Basically, what happens when the SSH daemon is started through its service, is
 * 1) the Linux kernel executes /sbin/init, resulting in the init process
 * 2) the init process executes /etc/init.d/sshd, resulting in this init service script running for a (short) while
 * 3) this sshd init service script executes /usr/sbin/sshd, resulting in the sshd daemon

For SELinux, with the common policy loaded, this could be noted as: [kernel_t] --(execute init_exec_t)--> [init_t] [init_t] --(execute initrc_exec_t)--> [initrc_t] [initrc_t] --(execute sshd_exec_t)--> [sshd_t]

What we are defining here are domain transitions from one domain to another, through the execution of a file.

When is a transition allowed
Now, such a transition can only occur when the following three requirements are satisfied.
 * 1) The origin domain has execute permission on the file
 * 2) The file context itself is identified as an entry point for the target domain
 * 3) The origin domain is allowed to transition to the target domain

If, and only if, all three requirements are satisfied, will such a domain transition be allowed to occur. Let's look at these three rules in more detail.

Execute permission on the file
As we have seen before, SELinux has a very fine-grained set of permissions that it can control. The execute permission on files is one of them. If a domain does not have execute permission on the file, then it will not be able to execute that file. Simple as that.

This too is a common source of denials or permission issues: a process tries to execute some file but is not allowed to. Again, as we learned in the past, this is very probably because of a wrong file context. On a Gentoo system, daemons that fail to execute files are most likely such problems because they are trying to execute a file with the lib_t context (often the case for files in somewhere) instead of the bin_t context.

So in case of the init script (initrc_t) calling the SSHd binary (sshd_exec_t):

Great, so the init service script is allowed to execute the SSHd binary.

Entrypoint permission for a domain on the file
By itself, executing a file with a specific label isn't sufficient to allow a domain transition. Remember that SELinux does not parse contexts itself - it has no knowledge that sshd_exec_t has anything to do with SSH daemons, let alone sshd_t. So we need to tell it that sshd_exec_t and sshd_t are related, by saying that the sshd_exec_t file is an entrypoint for the sshd_t domain.

As a counter-example, checking if ssh_exec_t (which is used for the SSH client) is known as an entrypoint for the SSH daemon (sshd_t) shows no hits:

What we can do is ask sesearch for what domains the ssh_exec_t type is an entrypoint for.

Process domain transition permission
The third requirement is that there must be an SELinux policy saying that that a transition from the source domain to the target domain is allowed. Let's look at the one from initrc_t to sshd_t:

Consider our previous example of the SSH client: the ssh_exec_t was entrypoint for multiple domains, including xm_ssh_t and nx_server_ssh_t. However, the domains that are allowed to execute the SSH client to transition to the xm_ssh_t and those that are allowed to execute the SSH client to transition to the nx_server_ssh_t are distinct.

What you need to remember
What you should remember from this tutorial is that
 * SELinux by default inherits contexts, be it from processes (on fork) or parent directories (on entry creation)
 * Context transition (change) can be triggered either by policy, by tools like runcon or via the SELinux API
 * Process context (domain) transition can happen only under the three conditions that
 * the target file context is executable for the source domain
 * the target file context is marked as an entrypoint for the target domain
 * the source domain is allowed to transition to the target domain