Linux Training : n. SELinux

SELinux

Security Enhanced Linux was initially developed by NSA. It was created to supplement the Discretionary Access Controls (DAC) which is the user, group, world, rwx method. SELinux implements Mandatory Access Controls (MAC) to the system at the kernel level. Where DAC will allow a user to set any file or directory to world read and write they own, the MAC model is outside of direct user controls and prevents mistakes such as this. The default for SELinux is to deny access. In order to obtain access, a rule or policy must exist that allows that access.

SELinux is the bread and butter security model around here. It is required learning. The RedHat SELinux documentation is a good starting place. The core products here use a policy called MLS which is backported from Fedora to RHEL. Read here on how MLS work as a SELinux policy and further Fedora SELinux docs. This explains the path to MLS security. The journal of the MLS developer at RedHat is an excellent background guide.

Dr. Rick Smith intro guide link is now http://www.cryptosmith.com/multilevel

A Google search on SELinux brings up lots of pages on how to turn off and/or disable SELinux.

DON'T DO THAT! BAD GOOGLE!

SELinux upstream source

The reference policy for SELinux is the source for the allowed access that ships with SELinux implementations for RHEL (and Fedora). It can be downloaded and studied but running it on a RHEL 5 workstation will be quite frustrating. Instead the FOOBAR INC policy should be used. It is available from the koji server. The default install has the policy source in /usr/share/selinux/devel/include.

SELinux files and commands

  • Files

    • The main location for SELinux configuration files are /etc/selinux. Within that directory are subdirectories for the various contexts (mls, strict and targeted) and a few configuration files for general selinux operations. config is the file that sets whether selinux is run at boot up and in what context. semanage.conf determines how libsemanage interacts with the policy manager. restorecond.conf lists locations for restorecond to watch in order to set defaults context at file creation time.
  • Commands

    /sbin/fixfiles
    /sbin/restorecon
    /sbin/setfiles
    /usr/bin/audit2allow
    /usr/bin/chcat
    /usr/bin/secon
    /usr/bin/semodule_deps
    /usr/bin/semodule_expand
    /usr/bin/semodule_link
    /usr/bin/semodule_package
    /usr/sbin/audit2why
    /usr/sbin/genhomedircon
    /usr/sbin/load_policy
    /usr/sbin/open_init_pty
    /usr/sbin/restorecond
    /usr/sbin/run_init
    /usr/sbin/semanage
    /usr/sbin/semodule
    /usr/sbin/sepolgen-ifgen
    /usr/sbin/sestatus
    /usr/sbin/setsebool
    /usr/bin/sesearch

    All of these have man pages. semanage is the central command that is used to fully manage the entire selinux policy and contexts.
  • ls -Z will show the SELinux context of a file or directory.
    As SELinux was originally written by the NSA, they are a good resource for writing SELinux policies.
    A more user friendly guide is here

SELinux overview

Once the admin gets some basic terminology under the belt, things become pretty clear.

  • context

    • every file has a context. This is the colon-delimited string from a ls -Z command.
      Some excerpts of file contexts

      - from the / directory
      drwxr-xr-x root root system_u:object_r:bin_t:s0 bin
      drwxr-xr-x root root system_u:object_r:boot_t:s0 boot
      drwxr-xr-x root root system_u:object_r:device_t:s0 dev
      drwxr-xr-x root root system_u:object_r:etc_t:s0 etc
      drwxr-xr-x root root system_u:object_r:home_root_t:s0 home
      - and from the /home directory
      drwx------ apps apps user_u:object_r:user_home_dir_t:s0 apps
      drwx------ jim users user_u:object_r:user_home_dir_t:s0 jim
      drwx------ jimtest jimtest user_u:object_r:user_home_dir_t:s0 jimtest
      drwxr-xr-x tomcat tomcat user_u:object_r:user_home_dir_t:s0 tomcat

    • contexts are composed of 4 parts
      • user_u
        • has nothing to due with the login name. The SELinux user identity is an identity known to the policy that is authorized for a specific set of roles, and for a specific MLS range. Each Linux user is mapped to an SELinux user via SELinux policy. This allows Linux users to inherit the restrictions placed on SELinux users. The mapped SELinux user identity is used in the SELinux context for processes in that session, in order to define what roles and levels they can enter.
          SELinux users
          /usr/sbin/semanage user -l
          
                          Labeling   MLS/       MLS/                          
          SELinux User    Prefix     MCS Level  MCS Range                      SELinux Roles
          
          root            user       s0         s0-s0:c0.c1023                 system_r sysadm_r user_r
          system_u        user       s0         s0-s0:c0.c1023                 system_r
          user_u          user       s0         s0-s0:c0.c1023                 system_r sysadm_r user_r
          
          login mappings
           /usr/sbin/semanage login -l
          
          Login Name                SELinux User              MLS/MCS Range            
          
          __default__               user_u                    s0                       
          root                      root                      s0-s0:c0.c1023 
          
      • role_r
        • Part of SELinux is the Role-Based Access Control (RBAC) security model. The role is an attribute of RBAC. SELinux users are authorized for roles, and roles are authorized for domains. The role serves as an intermediary between domains and SELinux users. The roles that can be entered determine which domains can be entered - ultimately, this controls which object types can be accessed. This helps reduce vulnerability to privilege escalation attacks.
      • type_t
        • also called the domain when referring to a process, otherwise a type but still is the third field (_t is optional but customary). The type is an attribute of Type Enforcement. The type defines a domain for processes, and a type for files. SELinux policy rules define how types can access each other, whether it be a domain accessing a type, or a domain accessing another domain. Access is only allowed if a specific SELinux policy rule exists that allows it.
      • level
        • The level is an attribute of MLS and Multi-Category Security (MCS). An MLS range is a pair of levels, written as lowlevel-highlevel if the levels differ, or lowlevel if the levels are identical (s0-s0 is the same as s0). Each level is a sensitivity:category pair, with categories being optional. If there are categories, the level is written as sensitivity:category.set. If there are no categories, it is written as sensitivity. Levels s0 through s15 for MLS (multi-level security) otherwise it's always s0. Categories are c0 through c1023. Contiguous category ranges are designated c0.c16. A comma separated list is used for non-contiguous ranges, c0,c3,c5,c25.c100.
  • The security is robust through a combination of Role-Based Access Control (RBAC), Type EnforcementĀ® (TE), and, optionally, Multi-Level Security (MLS). The default for SELinux is to not allow access. Rules are written to allow access.
  • Domain transition

    When a process needs to access either files or data from somewhere outside its own type, this requires a domain transition rule to allow access. Consider the following example:
New user changes their password
  • User perspective
  1. User enters passwd command at shell prompt
  2. User enters and then confirms the new password
  • System perspective
  1. shell forks a copy of itself and calls execve() to load the passwd program into the new copy
  2. passwd program verifies matching new passwords and writes to /etc/shadow
  • This is a domain transition.

    They are a very common process that gets handles at FOOBAR INC with SELinux Type Enforcement (TE) policy
    TE rules to allow password change

    allow unconfined_t passwd_exec_t : file {getattr execute};
    allow passwd_t passwd_exec_t : file entrypoint;
    allow unconfined_t passwd_t: process transition;

    This rule set allows the user the ability to change their password using the passwd command. Since /usr/bin/passwd is SUID root, we want to limit the access of the passwd binary. Since the deault SELinux action is to deny everything we need to write rules to allow passwd to operate and have read/write access to /etc/shadow. Since the user shell runs in the domain unconfined_t and the /usr/bin/passwd uses passwd_exec_t, the first rule allows that process an unconfined_t process to call an executable file of type passwd_exec_t. The second rule is an entry point rule. This is a key permission as it allows a program or process to "enter" a domain. By having only the passwd program labeled with the passwd_exec_t domain, this limits the files that passwd_t domain processes can act on to just the passwd binary. The passwd_t domain has read/write ability to shadow_t type files.
other passwd_exec_t binaries

The /usr/bin/chage is also set with passwd_exec_t type. This is because it is often called by the passwd program and so it shares much of the same SELinux rules

files vs processes

It is typical for the binary file itself to be in the foo_exec_t domain while the running process is in the foo_t domain. This way a single domain transition must occur for running the process as opposed to multiple domain transitions if more than one binary can start a process.

  • rule syntax

    The general form is allow from to : class { permission [LIN:, permission ]}
    Of course there is an exception: domain transitions are formed allow <to domain> <from domain> : class [LIN:options].

Network ports and SELinux

For targeted systems, the ports below 1024 are all marked reserved_port_t and all those over 1023 are marked port_t. So what if you need to add port access to a new application?

  • Check to see if there is already a domain associated with that port by running semanage port -l and grep for the port number.
    • If it's already listed then compare the output and see if you are installing the same service on that port. If so, all is good.
      • Associate the new application with the port type with chcon -t <port type> <path/to/newapp/binary>
    • If the port is not listed in the semanage data, then you will need add it under proper domain of the process.
      • semanage port -a -t <port domain> -p <type> <port number> where <type> is tcp or udp.
        • If the proper domain does not exist, this requires adding a new domain and compiling the module.
      • Now associate the new port and type with the new app.

Troubleshooting SELinux

  • audit2why

    This tool takes the AVC errors generated by SELinux and provides details about what failed and why. The typical source for this data is /var/log/audit/audit.log if auditd is running (which is normal for FOOBAR INC). This file accumulates all SELinux data, both success and failures. /usr/sbin/audit2why < /var/log/audit/audit.log will output a list of failure events and some text explaining what happened.
    Some example AVC alerts from audit2why
    type=AVC msg=audit(1273496538.411:12): avc:  denied  { read write } for  pid=3571 comm="nm-system-setti" path="socket:[9399]" dev=sockfs ino=9399 scontext=system_u:system_r:NetworkManager_t:s0 tcontext=system_u:system_r:system_dbusd_t:s0 tclass=tcp_socket
            Was caused by:
                    Missing or disabled TE allow rule.
                    Allow rules may exist but be disabled by boolean settings; check boolean settings.
                    You can see the necessary allow rules by running audit2allow with this audit message as input.
    
    type=AVC msg=audit(1273851397.042:693): avc:  denied  { name_bind } for  pid=28817 comm="nc" src=2222 scontext=user_u:system_r:tomcat_t:s0 tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket
            Was caused by:
                    Missing or disabled TE allow rule.
                    Allow rules may exist but be disabled by boolean settings; check boolean settings.
                    You can see the necessary allow rules by running audit2allow with this audit message as input.
    
    The numbers in the ()'s are timestamps and a rule identifier is after the :.
  • audit2allow

    This will print out a command to run to allow the process to function. This is typically OK for desktop users in targeted mode but is often too permissive for the high-security needs of our customers.
  • SELinux Policy Analysis

    A gui tool called apol is in the default yum repo that is very useful at looking at how the current system is setup. It can be installed and run from a command shell with apol. You will need to run "File"->"Open" and then load the current policy file from /etc/selinux as well as select "File Contexts* then "Create and Load" and save an index file somewhere in /tmp and let the tool generate it from "/". The only thing missing is the "Attributes" as text since they are not saved into the binary format.
Simple SELinux exercise
  1. Open up a command shell, become the local root user, copy /usr/bin/nc to /usr/local/bin/nc_test. Stay local root in this shell
  2. In a second shell, also become local root. This will be where you will test SELinux status on the exercise
  3. In the first shell launch a test with /usr/local/bin/nc_test -l 2222. This should work with no errors.
  4. In a third shell as a normal user launch */usr/bin/nc localhost 2222 and then enter some text. It should appear in the first shell STDOUT.
  5. In the second shell use lsof to find the context of the nc_test that is running.
  6. Exit both the nc and the nc_test processes.
  7. Now change the domain of the nc_test binary to httpd_exec_t
  8. Find the allowed ports for http_t
  9. Open nc_test in listen mode on an allowed port from shell 1.
  10. Open an nc from shell 3 to the same port
  11. Analyze the running ports
  12. Now close all open nc and nc_test and change the domain of nc_test to tomcat_exec_t and relaunch the listener on port 32001
  13. Reanalyze the port connection or failure using lsof or audit2why
  14. Devise a method to allow this connection to occur only on the 32001 port.
    1. delete /usr/local/bin/nc_test when finished