Lab 03a - SELinux, The Bare Essentials

Introduction

SELinux is a complex beast that the average administrator will never fully understand or tame. That said, it is a very important security tool that we need to learn to live with. The good news is that all the heavy lifting of configuring the policy used to protect our system is done for us by the RedHat/CentOS teams. All we need to do is learn how to live in harmony with this powerful guard dog.

In this lab we will learn how to recognize and remedy some of the most common headaches SELinux gives admins. This lab will not make you and SELinux expert. It should give you the skills to turn SELinux on without breaking into a cold sweat.

It is recommended that you review the Security-Enhanced Linux Users Guide found on the redhat documentation site.


Prerequisites:

Before you start this lab you must have:


Overview:

We will use earth from previous lab.


Part A: Configure earth


Part C: Let's See SELinux do it's thing

The main purpose of the SELinux targeted policy is to ensure that certain key system processes, like httpd, are only allowed to access resources, like files and ports, that are safe. If an attacker takes control of the httpd daemon process, we do not want them to be able to look around the file system. SELinux limits the access of httpd to files with specific SELinux types. Let's see how that works..

  1. The page from the safe location should still be accessible...
    curl http://localhost/1.html
    
  2. The page from the new unsafe location should not be accessible... (403 error expected)
    curl http://localhost/web/1.html
    
  3. Seeing the 403 error, our first instinct to to check the file permissions.
    ll -l /web
    ll -ld /web
    
    That can't be the problem both are world readable.
  4. Next we'd likely check the httpd error log.
    tail /var/log/httpd/error_log
    
    it will show something like..
    [Fri Dec 30 15:21:01.144450 2022] [core:error] [pid 1202:tid 140093408352000] (13)Permission denied: [client ::1:51638] AH00035: access to /web/1.html denied (filesystem path '/var/www/html/web/1.html') because search permissions are missing on a component of the path
    
    As we expected httpd can't access /web, but we get no additional hint as to why. This is where an admin unfamiliar with SELinux is likely to become perplexed.
  5. We know a little about SELIUNX, so we look in /var/log/audit/audit.log for messages with a type of AVC
     grep AVC /var/log/audit/audit.log
    
    should show something like...
    type=AVC msg=audit(1672431661.143:124): avc:  denied  { getattr } for  pid=1202 comm="httpd" path="/web/1.html" dev="dm-0" ino=87 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
    
    This tells us that SELinux has intervened. This tutorial will give a little more detail. (Archived version)
    In short...
    FieldTells us
    comm="httpd" Offending executable.
    path="/web" Resource that was denied
    scontext=system_u:system_r:httpd_t:s0 The source context, or "who SELinux thinks is asking"
    tcontext=system_u:object_r:default_t:s0 The target context, or "what SELinux thinks is being asked for"
  6. The power of Z
    The command line switch Z adds SELinux information to many commands. Try these...
    ls -lZ /var/www/html/1.html
    ps -eflZ |grep httpd
    id -Z
    

Part D: Make /web/ accessible to httpd using chcon

A comparison of /web/1.html and /var/www/html/1.html will show us what needs to change.

Consider the results of these commands...
[root@tina ~]# ll -Z /var/www/html/1.html
rw-r--r--. 1 root root unconfined_u:object_r:httpd_sys_content_t:s0 38 Dec 30 15:14 /var/www/html/1.html
[root@tina ~]# ll -Z /web/1.html
-rw-r--r--. 1 root root unconfined_u:object_r:default_t:s0 38 Dec 30 15:14 /web/1.html
We can see that the only difference between these two files, from an SELinux viewpoint, is that they have different types. If we could get /web/1.html to have the same type, httpd_sys_content_t, as /var/www/html/1.html, all would be good. We have two ways of changing this type. One will survive a re-labeling, and one will not. Either will survive a reboot.
  1. For a quick fix that will not survive a re-labeling we can use the chcon command like this...
    chcon -Rv -t httpd_sys_content_t /web
    
  2. Verify that this worked using curl
  3. Reboot earth
  4. Verify that we can still access /web/1.html curl

Part E: Make our type change more permanent

You may recall that when we switched SELinux to enforcing mode it took a while for the system to boot. This was because the mode change triggered a full file system relabeling. The context of a file is stored in the file system as an extended attribute. But it is the SELinux policy, targeted in our case, that defines what the context of any given file should be. The targeted policy says that /web and everything below it shoud have a type of default_t. If a full file system relabeling is triggered /web and all it's contents will revert to a type of default_t and no longer be accessible to httpd.

If we want to make /web available to httpd on a truly permanent basis, we should modify the targeted policy telling it "/web should have a type of httpd_sys_content_t.

  1. Tell SELinux to restore the context of /web and it's contents to it's default value.
    restorecon -Rv /web
    
  2. Use curl to verify that /web/1.html is no longer readable by httpd
    curl http://localhost/web/1.html
    
  3. We will use the semanage command to modify the targeted policy, but first we need to install semanage
    yum install policycoreutils-python-utils
    
  4. Modify the targeted policy
    semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
    
  5. Tell SELinux to restore the context of /web and it's contents to it's new default value.
    restorecon -Rv /web
    
  6. Check our work (curl should succeed)
    curl http://localhost/web/1.html
    

Part F: Allow httpd to listen on a non-standard port

SELinux can restrict access to ports just like it restricts access to files. In this section we will make earth listen on port 9317.

  1. Start by checking which ports httpd is allowed to listen on by default.
    semanage port -l|grep http
    
  2. Since port 9317 is not listed, we expect that httpd will no be allowed access it. Let's verify that.
  3. Use semanage to allow httpd to access TCP port 9317
    semanage port -a -t http_port_t -p tcp 9317
    
  4. Start httpd
  5. Check our work
    curl http://localhost:9317/1.html
    

Part G: Grading