This blog post is originally written by Srinivas Gowda G from Dell Linux Engineering group

Dell recently announced support for RHEL7 on Dell PowerEdge Servers. As is the case with any SELinux (Security Enhanced Linux) enabled OS, your applications might hit SELinux surprises with RHEL7. Applications that ran perfectly well on RHEL6 might now complain about SELinux denials in RHEL7.  Most of the time when faced with SELinux issues the first temptation is to disable SELinux or switch to Permissive mode. Not the best thing to do!!! .

In this article I intend to give an overview of SELinux architecture, demonstrate usage of some of the SELinux utilities available as part of RHEL7 and a few pointers on how best to deal with SELinux denials. SELinux provides an excellent Access Control Mechanism built into Linux. It was originally developed by US National Security Agency but is now part of various Linux distributions including RHEL7 providing enhanced security to Linux operating systems.

Most Linux users are familiar with DAC (Discretionary Access Control),  the various degrees of permission levels that can be assigned to files in Linux as shown in this quick example:

$ ls -l foo 

  -r-xr-xr-x  1 test testgroup   112 Oct  3  2013 foo.txt

SELinux implements Mandatory Access Control (MAC) over the existing DAC.  In DAC the owner of the object specifies which subjects can access the object. Say for the above file foo, you want to give read and write permission to all the users and groups, and also in addition provide execution permission to user “test”. We can use chmod command to provide these permissions 

$ chmod 766 foo

$ ls -l foo

   -rwxrw-rw-  1 test testgroup   112 Oct  3  2014 foo.txt

As we see in DAC, control of access to files is based on the discretion of the owner. Access is controlled based on Linux user and group IDs. 

Configuring SELinux

One of the important file in the configuration space is /etc/selinux file, here is a sample output of the default setting you might find in RHEL7

# This file controls the state of SELinux on the system.

# SELINUX= can take one of these three values:

#     enforcing - SELinux security policy is enforced.

#     permissive - SELinux prints warnings instead of enforcing.

#     disabled - No SELinux policy is loaded.

SELINUX=enforcing

# SELINUXTYPE= can take one of these two values:

#     targeted - Targeted processes are protected,

#     minimum - Modification of targeted policy. Only selected processes are protected.

#     mls - Multi Level Security protection.

SELINUXTYPE=targeted 

To make persistent changes of SELinux status or protection type (MLS/targeted) you must first edit the /etc/selinux configuration file and restart the operating system.

By default RHEL7 enables SELINUX in enforcing mode and SELINUXTYPE is targeted. There are good numbers of utilities that can be used to play around SELinux; I’ll try to cover as much as possible in this blog and restrict myself with the default “targeted” policy.

sestatus utility can be used to check the current status of SELinux on your RHEL7 system.

$ sestatus

SELinux status:                 enabled

SELinuxfs mount:                /sys/fs/selinux

SELinux root directory:         /etc/selinux

Loaded policy name:             targeted

Current mode:                   enforcing

Mode from config file:          enforcing

Policy MLS status:              enabled

Policy deny_unknown status:     allowed

Max kernel policy version:      28

setenforce can be used to change the selinux mode in a non-persistent way.

$ setenforce

  usage:  setenforce [ Enforcing | Permissive | 1 | 0 ]

Similarly getenforce utility can be used to get the status of SELinux

$ getenforce

Enforcing

Security Context

Each file, users and process on a SELinux enabled system has a Security label called context associate with it. Here are some examples of how you can check the context of a file, process or users

 If I were to look at the SELinux context of /bin then you can use ls -dZ or you can prefer to use secon which is more descriptive.

$ secon -f /bin/

     user: system_u

     role: object_r

     type: bin_t

     sensitivity: s0

     clearance: s0

     mls-range: s0

 In this example we have a file myFile for which SELinux provides a user (unconfined_u), a role (object_r), a type (user_home_t), and a level (s0) and it is this information that are used to make the access control decision in SELinux.

$ ls -Z myFile

-rw-rw-r--. user1 group1 unconfined_u:object_r:user_home_t:s0 file1

Similarly for a process whose PID is 3161 you can check the SELinux context

$ secon -p 3161  ( or use ps –eZ)

user: unconfined_u

role: unconfined_r

type: unconfined_t

sensitivity: s0

clearance: s0:c0.c1023

mls-range: s0-s0:c0.c1023

sestatus and secon is part of policycoreutils package. To list SELinux confined users

$ semanage user -l

                Labeling   MLS/       MLS/                         

SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles

guest_u            user       s0              s0                                   guest_r

root                  user       s0              s0-s0:c0.c1023               staff_r sysadm_r system_r unconfined_r

staff_u              user       s0             s0-s0:c0.c1023                staff_r sysadm_r system_r unconfined_r

sysadm_u         user       s0             s0-s0:c0.c1023                sysadm_r

system_u         user       s0              s0-s0:c0.c1023                system_r unconfined_r

unconfined_u   user       s0              s0-s0:c0.c1023                system_r unconfined_r

user_u             user       s0              s0                                    user_r

xguest_u          user      s0              s0                                     xguest_r

 semanage login -l gives the mapping between SElinux and linux users

$ semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

 __default__          unconfined_u         s0-s0:c0.c1023           *

 root                      unconfined_u         s0-s0:c0.c1023           *

 system_u              system_u              s0-s0:c0.c1023           *

The default SELinux policy used in RHEL7 is "Targeted Policy". In targeted policy, type translates to a domain for a process and type for a file. An executable of type_t transitions to a domain domain_t as defined by Entry point permissions defined in policy tables. If you wish to change security labels then you can do so by using chcon or semanage utility. Changes made using chcon is not persistent and is lost when file systems are relabeled.  If you are dealing with SELinux related issues it is very important that you know how to set correct or appropriate context to files and directories. This will help you solve majority of SELinux denials.

The following example tries to demonstrate these steps. I have a user “linux” whose home directory has a folder called Music already present

 # Directory Music has type audio_home_t

$ ls -dZ

  drwxr-xr-x. linux linux unconfined_u:object_r:audio_home_t:s0 Music

 # Now I will create a dummy file file1 inside "Music" folder and check the context of this new file.

$ touch Music/file1

$ ls -dZ Music/

-rw-rw-r--. linux linux unconfined_u:object_r:audio_home_t:s0 file1

 # Let’s use chcon to relabel security label type of directory "Music" from audio_home_t to admin_home_t

$ chcon -t admin_home_t Music

$ ls -dZ Music/

drwxr-xr-x. linux linux unconfined_u:object_r:admin_home_t:s0 Music

 #Now that we have relabeled, lets create file2 inside "Music" 

$ touch Music/file2

 #unlike file1 which had "audio_home_t" , we now see that the file2 is labeled as "admin_home_t" which is same as its parent directory

$ ls -Z Music/

-rw-rw-r--. linux linux unconfined_u:object_r:audio_home_t:s0 file1

-rw-rw-r--. linux linux unconfined_u:object_r:admin_home_t:s0 file2

 restorecon is a SELinux utility that is mainly used to reset the security context of files or directories. It only modifies type portion of the security context of objects with preexisting labels.

# Restore files to default SELinux security contexts. All the previous changes will be reverted.

$ restorecon -R .   

# We now can see that both Music and files inside this directory are relabeled to the default values.

$ ls -dZ Music/

  drwxr-xr-x. linux linux unconfined_u:object_r:audio_home_t:s0 Music

$ ls -Z Music/

  -rw-rw-r--. linux linux unconfined_u:object_r:audio_home_t:s0 file1

  -rw-rw-r--. linux linux unconfined_u:object_r:audio_home_t:s0 file2

You can’t relabel files with arbitrary types.

$ chcon -t dummy_type_t Music/file1

  chcon: failed to change context of Music/file1 to unconfined_u:object_r:dummy_type_t:s0 : Invalid argument

However new types can be created by writing new policy rules

If you are wondering how to validate the correctness of security context of objects then refer to matchpathcon utility. matchpathcon utility can be used to check the default security context associated with a file. matchpathcon queries the system policy to find out the correct context to files and reports the same.

$ matchpathcon -V /home/linux/Music/file2

  /home/linux/Music/file1 has context unconfined_u:object_r:admin_home_t:s0, should be unconfined_u:object_r:audio_home_t:s0

By now you must be wondering where these context rules are defined. In RHEL7 /etc/selinux/targeted/contexts is where the context of all the files is defined.

As we have seen, changes made via chcon are not persistent. Non default changes made via chcon can be reverted using restorecon utility. semanage fcontext command is used to persistently set the context of files. Similar to the example above let’s try to change the context of a file, but this time let’s do a persistent change.

# Lets create a folder called config under /root

$ mkdir config

# By default policy labels the directory as admin_home_t

$ ls -Zd config/

  drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 config/

 

# Lets relabel to config_home_t

$ chcon -t config_home_t config/

# As expected matchpatcon complains about the wrong context because default policy for config directory under /root must be admin_home_t

$ matchpathcon -V config/

  config has context unconfined_u:object_r:config_home_t:s0, should be system_u:object_r:admin_home_t:s0

 

# Using restorecon the context reverts back to the default target label as defined by the policies

$ restorecon -v config/

$ restorecon reset /root/config context unconfined_u:object_r:config_home_t:s0->unconfined_u:object_r:admin_home_t:s0

# Now let’s write a new security context rule that will relabel "config" folder under root to config_home_t

$ ls -Zd config/

  drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 config/

$ semanage fcontext -a -t config_home_t  "/root/config"

$ restorecon -R -v .

  restorecon reset /root/config context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:config_home_t:s0

$ ls -Zd config/

  drwxr-xr-x. root root unconfined_u:object_r:config_home_t:s0 config/

# Let`s create files under /root/config/ folder and check its context

$ touch foo1

$ touch foo2.config

# Here foo1 and foo2.config seems to inherit the context as its parent directory

$ ls -Z config/*

  -rw-r--r--. root root unconfined_u:object_r:config_home_t:s0 config/foo1

  -rw-r--r--. root root unconfined_u:object_r:config_home_t:s0 config/foo2.config

# Let’s say I want only files inside /root/config  with .config extension to have security context as config_home_t

$ semanage fcontext -a-a -t config_home_t  "/root/config(/.*\.config)"

$ restorecon -R -v .

  restorecon reset /root/config/foo1 context unconfined_u:object_r:config_home_t:s0->unconfined_u:object_r:admin_home_t:s0

 

$ ls -Z config/

  -rw-r--r--. root root unconfined_u:object_r:admin_home_t:s0 foo1

  -rw-r--r--. root root unconfined_u:object_r:config_home_t:s0 foo2.config

You must be able to find all these new rules added under "file_contexts.local"

$ cat /etc/selinux/targeted/contexts/files/file_contexts.local

 # This file is auto-generated by libsemanage

 # Do not edit directly.

 /root/config    system_u:object_r:config_home_t:s0

 /root/config(/.*\.config)    system_u:object_r:config_home_t:s0

Now that we have managed to modify the security context of files let’s move on to the other most useful technique to solve SELinux denials. 

Booleans

SELinux provides a set of Booleans that helps change some of the SELinux policies.  semanage boolean -l  lists SELinux policies that can be changed at run time. Booleans are pretty useful since changes can be made easily without writing policies.

getsebool -a  is used to list the current status of the these Booleans, setsebool can be used change the status of the available Booleans

 

$ getsebool puppetmaster_use_db

  puppetmaster_use_db --> off

$ setsebool -P puppetmaster_use_db on

$ getsebool puppetmaster_use_db

  puppetmaster_use_db --> on

  -P flag make these settings to be persistent across reboots.

If you are interested to know all the existing SELinux rules on your system then there is utility called sesearch which helps you find that(use --all to list all the rules). sesearch is part of setools-console package which contains other useful utilities such as findcon, seinfo etc..  

Access Vector Cache (AVC)

SElinux policies are always evolving, new rules might get added while old ones may get refined or removed. This invariably means SELinux denying access to some operations of your application. These denials are usually referred as AVC denials.

SELinux uses a cache called Access Vector Cache (AVC) that caches all the successful and failure access.  These AVC denials are usually logged in /var/log/audit/audit.log, they can also be logged in system logs but it depends on which demons are running (auditd, rsyslogd, setroubleshootd). In an X windows system if you have setroubleshootd and auditd running, then a warning message is displayed on the console. If you do not have a GUI console, then you can either use ausearch which is part of audit package or inspect the audit.log or system log using good old “grep”.

SELinux provides an easy way to fix the denials using audit2allow. This is a pretty helpful utility that generates SELinux policy using the audit logs and get rid of the denials. But using this is something that you want to avoid if you are not sure about the policies are being added.  Most of the denials can be dealt by either changing the context of files in conflict or enabling the available Booleans. If these two changes don’t take care of your denials then care must be taken before you start adding new policies. 

RHEL7 Update

Some of the RHEL7 features such as systemd will trigger changes in security context of your applications in RHEL7, care must be taken by application owners when developing or porting applications to RHEL7. It’s important to understand the context transition of process and files. “sepolicy transition” command can be used to generate a process transition report. RHEL7 has addressed some of the File name transition issues of SELinux. If you are looking for more detailed information of SELinux on RHEL7 then refer to SELinux_Users_and_Administrators_Guide , and this document also provides an overview of new SELinux features in RHEL7.