This article discusses security contexts for subjects (typically, processes) and how they are assigned. To view the list of processes on your system, along with their hierarchy, use the pstree
command:
[root@vbg-work ~]# pstree
init-+-NetworkManager-+-dhclient
| `-{NetworkManager}
|-abrtd
|-acpid
|-atd
|-auditd-+-audispd-+-sedispatch
| | `-{audispd}
| `-{auditd}
|-avahi-daemon---avahi-daemon
|-bonobo-activati---{bonobo-activat}
|-cimserver---3*[{cimserver}]
|-clock-applet
|-console-kit-dae---63*[{console-kit-da}]
|-crond
|-cupsd
|-2*[dbus-daemon---{dbus-daemon}]
|-2*[dbus-launch]
|-devkit-disks-da---devkit-disks-da
|-devkit-power-da
|-evolution---7*[{evolution}]
|-evolution-alarm---{evolution-alar}
|-evolution-data----2*[{evolution-data}]
|-gconf-im-settin
|-gconfd-2
|-gdm-binary---gdm-simple-slav-+-Xorg
| `-gdm-session-wor---gnome-session-+-abrt-applet
| |-bluetooth-apple
| |-gdu-notificatio
| |-gnome-panel---{gnome-panel}
| |-gnome-power-man
| |-gnome-volume-co
| |-gpk-update-icon---{gpk-update-ico}
| |-metacity---{metacity}
| |-nautilus---{nautilus}
| |-nm-applet
| |-polkit-gnome-au
The above output shows the process tree on my system (starting with the init
process). init
is the first one to be executed by the kernel after the basic system has been set up. All processes are children ofinit
. When the system is shut down, init
is the last process to terminate before the kernel executes its own shutdown.
To view the security contexts allotted to all system processes, execute the pstree
command with the -Z
option:
[root@vbg-work ~]# pstree -Z
init(`system_u:system_r:init_t:s0')
|-NetworkManager(`system_u:system_r:NetworkManager_t:s0')
| |-dhclient(`system_u:system_r:dhcpc_t:s0')
| `-{NetworkManager}(`system_u:system_r:NetworkManager_t:s0')
|-abrtd(`system_u:system_r:abrt_t:s0-s0:c0.c1023')
|-acpid(`system_u:system_r:apmd_t:s0')
|-atd(`system_u:system_r:crond_t:s0-s0:c0.c1023')
|-auditd(`system_u:system_r:auditd_t:s0')
| |-audispd(`system_u:system_r:audisp_t:s0')
| | |-sedispatch(`system_u:system_r:audisp_t:s0')
| | `-{audispd}(`system_u:system_r:audisp_t:s0')
| `-{auditd}(`system_u:system_r:auditd_t:s0')
|-avahi-daemon(`system_u:system_r:avahi_t:s0')
| `-avahi-daemon(`system_u:system_r:avahi_t:s0')
|-bonobo-activati(`unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023')
| `-{bonobo-activat}(`unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023')
|-cimserver(`system_u:system_r:initrc_t:s0')
| |-{cimserver}(`system_u:system_r:initrc_t:s0')
| |-{cimserver}(`system_u:system_r:initrc_t:s0')
| `-{cimserver}(`system_u:system_r:initrc_t:s0')
|-clock-applet(`unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023')
|-console-kit-dae(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
| |-{console-kit-da}(`system_u:system_r:consolekit_t:s0-s0:c0.c1023')
Now, we can see the security contexts associated with all the processes. How did init
get a type ofinit_t
? Why are the security contexts of some child processes different from those of the parent (else all processes in the system should have had the type init_t
)? How are these different security types assigned?
Consider another scenario: The httpd
process on a Fedora/RHEL server is started with the commandservice httpd start
or /etc/init.d/httpd start
. Start the Web server process, if it’s not already running, with the following command:
[root@vbg-work ~]# /etc/init.d/httpd start
Check the security context associated with the httpd
process:
[root@vbg-work ~]# ps axZ | grep httpd
unconfined_u:system_r:httpd_t:s0 3099 ? Ss 0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 3102 ? S 0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 3103 ? S 0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 3104 ? S 0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 3105 ? S 0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 3106 ? S 0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 3107 ? S 0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 3108 ? S 0:00 /usr/sbin/httpd
unconfined_u:system_r:httpd_t:s0 3109 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3113 pts/0 S+ 0:00 grep httpd
As you can see, the httpd
process gets a security context type of httpd_t
.
Stop the Web server with the following command:
[root@vbg-work ~]# service httpd stop
Stopping httpd: [ OK ]
Restart the Web server. But this time, not from the service
start-up script, but by executing the binary command, which is as follows:
[root@vbg-work ~]# /usr/sbin/httpd
…and now, check the SELinux security context for the Web server process:
[root@vbg-work ~]# ps axZ | grep httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3207 ? Ss 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3209 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3210 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3211 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3212 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3213 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3214 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3215 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3216 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 3218 pts/0 S+ 0:00 grep httpd
[root@vbg-work ~]#
This time, the type of the Web server process is unconfined_t
. Why is it so?
If we use the service
command, the same Web server process gets a security context type of httpd_t
, but executing the Web server directly gives the Web server process a security context type ofunconfined_t
.
As you would have probably guessed by now, this is due to Type Transitioning. Like objects (files), Type Transitioning is also applied to subjects (processes).
The basic rules to set the security context of services are the same as those for files: Whenever a new service (process) is created in the memory, Type Transition rules in the policy are checked. If a Type Transition rule exists and matches the conditions, the resulting process is given the new security context. When there are no such rules, the new process inherits the security context of its parents.
To check all Type Transitions rules that apply to processes (classes of type process), issue the following commands:
[root@vbg-work ~]# sesearch -T -c process
type_transition user_wine_t fusermount_exec_t : process mount_t;
type_transition staff_execmem_t nsplugin_config_exec_t : process nsplugin_config_t;
type_transition insmod_t fusermount_exec_t : process mount_t;
type_transition xend_t fusermount_exec_t : process mount_t;
type_transition sysadm_java_t fusermount_exec_t : process mount_t;
type_transition ricci_modservice_t fail2ban_initrc_exec_t : process initrc_t;
type_transition init_t afs_bosserver_exec_t : process afs_bosserver_t;
type_transition hotplug_t dictd_initrc_exec_t : process initrc_t;
type_transition ricci_modservice_t sssd_initrc_exec_t : process initrc_t;
type_transition init_t apmd_exec_t : process apmd_t;
type_transition qmail_local_t qmail_queue_exec_t : process qmail_queue_t;
type_transition staff_execmem_t gpg_agent_exec_t : process gpg_agent_t;
...
Based on the above rules, the syntax of Type Transition rules that apply to processes can be understood as:
type_transtion [Parent Process Type] [Type of File being executed to create a process] : process [Type of The New Process created]
To check the above rules, let us look at the example of the Web server process discussed earlier. When executing the executable /usr/sbin/httpd
directly to create the httpd
process:
- The parent process is the shell (because we are executing the command
/usr/sbin/httpd
under the Bash shell).
- The type of the parent process is
unconfined_t
. (Execute the following command to check.)[root@vbg-work ~]# ps axZ | grep bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2460 pts/0 Ss 0:00 bash
- The type of the file being executed is
httpd_exec_t
. (Execute the following command to check.)[root@vbg-work ~]# ls -lZ /usr/sbin/httpd
-rwxr-xr-x. root root system_u:object_r:httpd_exec_t:s0 /usr/sbin/httpd
Let us check in our policy if such a rule exists:
[root@vbg-work ~]# sesearch -T -c process | grep httpd_exec_t | grep unconfined_t
[root@vbg-work ~]#
This shows that we do not have a Type Transition rule to set the security context of new processes created by executing files of type httpd_exec_t
under a parent process of type unconfined_t
. In such a scenario, i.e., in the absence of any Type Transition rule, the new process takes the type of the parent; therefore, the httpd
process inherits its security context from Bash (which is unconfined_t
).
Let us now analyse the other case. When starting the httpd
service through initialisation scripts:
- The parent process is the shell (because we are executing the script
/etc/init.d/httpd
under Bash).
- The type of the parent process is
unconfined_t
. (Execute the following command to check.)[root@vbg-work ~]# ps axZ | grep bash
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 2460 pts/0 Ss 0:00 bash
- The type of the file being executed is
httpd_initrc_exec_t
. (Execute the following command to check.)[root@vbg-work ~]# ls -lZ /etc/init.d/httpd
-rwxr-xr-x. root root system_u:object_r:httpd_initrc_exec_t:s0 /etc/init.d/httpd
Let us check in our policy if such a rule exists:
[root@vbg-work ~]# sesearch -T -c process | grep httpd_initrc_exec_t | grep unconfined_t
type_transition unconfined_t httpd_initrc_exec_t : process initrc_t;
[root@vbg-work ~]#
Finally, we have found a match. This rule states that if a file of type httpd_initrc_exec_t
is executed under a parent process of type unconfined_t
, the resulting process should get a type of initrc_t
.
This is good, but we had observed that the Web server process had a type of httpd_t
and this rule states that the type of the resulting process is initrc_t
. Is there an error? Is there something missing?
There is, indeed, something missing. It is important to note that the Web server process is created on executing the binary file (/use/bin/httpd
). Therefore, the init
script actually executes this file.
But what happens is that the shell script process created by executing the initialisation script (/etc/init.d/httpd
) is now running with a process security context bearing the type initrc_t
(as per the rule above). When this process further executes the Web server binary (/usr/sbin/httpd
), a new context is created. Therefore, there is another scenario that comes into play here, which is:
- The parent process is the shell script process created by executing the script
/etc/init.d/httpd
.
- The type of the parent process is
initrc_t
(because this is the type of process created by executing the init
script from under Bash, as per the Type Transition rule above).
- The type of the file being executed is
httpd_exec_t
(as the shell script further executes the binary/usr/sbin/httpd
). Execute the following command to check:[root@vbg-work ~]# ls -lZ /usr/sbin/httpd
-rwxr-xr-x. root root system_u:object_r:httpd_exec_t:s0 /usr/sbin/httpd
Let us see if we have a Type Transition rule in the policy for the above:
[root@vbg-work ~]# sesearch -T -c process | grep httpd_exec_t | grep initrc_t
type_transition initrc_t httpd_exec_t : process httpd_t;
[root@vbg-work ~]#
Voila! There it is, stating that if a file of type httpd_exec_t
is executed under a parent process of typeinitrc_t
, the resulting process created will have a security context type of httpd_t
.
As an exercise, let us ensure that the httpd
process, if executed directly under the shell, should also be created with a security context type of httpd.
To do this, we will need to create a new module and insert it into our policy. We will need to create a new type enforcement file as discussed in earlier articles. An example of the file is given below:
vbg@vbg-work test-selinux]$ cat http.te
policy_module(http-lfy,1.1.0)
########################################
#
# Declarations
#
require {
type httpd_t;
type unconfined_t;
type httpd_exec_t;
role unconfined_r;
class process transition;
}
########################################
#
# http local policy
#
type_transition unconfined_t httpd_exec_t : process httpd_t;
role unconfined_r types httpd_t;
allow unconfined_t httpd_t:process transition;
[vbg@vbg-work test-selinux]$
Compile and load this module:
[vbg@vbg-work test-selinux]$ make http.pp
[vbg@vbg-work test-selinux]$ su -
[root@vbg-work ~]# semodule -i /home/vbg/test-selinux/http.pp
Now execute the command /usr/sbin/httpd
and note the security context type of the httpd
process:
root@vbg-work ~]# /usr/sbin/httpd
[root@vbg-work ~]#
[root@vbg-work ~]# ps axZ | grep http
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4343 ? Ss 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4345 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4346 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4347 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4348 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4349 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4350 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4351 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:httpd_t:s0-s0:c0.c1023 4352 ? S 0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4354 pts/0 S+ 0:00 grep http
[root@vbg-work ~]#
But how is the type of the first process (init) set? Does it inherit its type from the kernel? What exactly happens?
The following lines are taken verbatim from
Dan Walsh’s blog: “When the SELinux kernel boots up, it is hard coded to run as
kernel_t
. Since at this point there is no policy running, this is the only context. So since this is the only context, all applications that are run will stay in
kernel_t
. When the kernel executes
/sbin/init
it originally is running as
kernel_t
, then it reads in the policy file and loads it into the kernel. At this point init re-execs itself. When
/sbin/init
was installed it is labelled
init_exec_t
and now there is a rule in the kernel that says when
kernel_t
execs an application labelled
init_exec_t
, it should transition to
init_t
. So now the
init
process is running as
init_t
.”
Let us check if such a rule really exists in the policy, which applies when
init
re-executes itself:
- The parent process is the kernel.
- The parent process type is
kernel_t
.
- The file being executed is
/sbin/init
.
- The security context type of the file being executed is
init_exec_t
:[root@vbg-work ~]# ls -lZ /sbin/init
-rwxr-xr-x. root root system_u:object_r:init_exec_t:s0 /sbin/init
Search the SELinux policy for a Type Transition rule:
root@vbg-work ~]# sesearch -T -c process | grep init_exec_t | grep kernel_t
type_transition kernel_t init_exec_t : process init_t;
There we are! When /sbin/init
is executed under kernel_t
, the init
process being created has a type of init_t
. This can be checked by the following command:
[root@vbg-work ~]# pstree -pZ | head -n 1
init(1,`system_u:system_r:init_t:s0’)
[root@vbg-work ~]#
Now we can understand how subjects or processes created in memory get their security contexts. Applying SELinux policy rules under type enforcement is simply allowing access only to desired objects by the designated subjects, and once we know how to set the security context types of objects and subjects, and how to create allow rules, we can easily achieve the best out of SELinux.
In the next article in this series, we will explore macros and dive deep into them.