Yesterday I was having a chat with the lads in the office about properly using SELinux. I realised later that I haven’t written down a short quick start guide on the topic, so here we go.
There seems to be an undesirable corporate standard in many organisations these days to simply disable SELinux because “its too complicated”. This article is designed to give you the information you need to not just challenge that stereotype, but also to change things for the better.
If you are unfamiliar with SELinux, here is a general background from Wikipedia.
“Security-Enhanced Linux (SELinux) is a Linux feature that provides the mechanism for supporting access control security policies, including United States Department of Defense-style mandatory access controls, through the use of Linux Security Modules (LSM) in the Linux kernel. It is not a Linux distribution, but rather a set of kernel modifications and user-space tools that can be added to various Linux distributions. Its architecture strives to separate enforcement of security decisions from the security policy itself and streamlines the volume of software charged with security policy enforcement.[1][2] The key concepts underlying SELinux can be traced to several earlier projects by the United States National Security Agency.
It has been integrated into the mainline Linux kernel since version 2.6, on 8 August 2003.” — Wikipedia.org
Topics
I will be covering the below topics in this article.
- SELinux Modes
- Enabling and disabling SELinux
- Checking, Changing and Restoring SELinux contexts
- Creating your own SELinux policy
- Monitoring and troubleshooting
SELinux Modes
SELinux can be set to one of 3 different modes.
“Enforcing” is most desirable and the most restrictive.
Enforcing mode is the most secure of the three modes. It will block/deny any form of violation that the kernel detects and by default, log those details in /var/log/audit/audit.log
If you are running custom applications in your environment, SELinux may have a field day in blocking all sorts of nastys if you don’t enable SELinux to allow parts of your application to function.
“Permissive” mode means that SELinux is enabled, but it is not actively blocking any violations.
Permissive mode is great for testing and auditing whilst you configure your systems to run in Enforcing mode. Although things are not blocked, all details are logged to /var/log/audit/audit.log
“Disabled” mode is exactly what the name implies.
SELinux will not block any voilations nor will it generate any logs.
Enabling and disabling SELinux
There are two ways to enable and disable SELinux and there are differences in each method.
Firstly, the default system mode in /etc/selinux/config or /etc/sysconfig/selinux depending on your Linux distribution.
Here is my current configuration.
[mac@rhodey ~]$ cat /etc/sysconfig/selinux # 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 [mac@rhodey ~]$
We can see from the above, that my default system behaviour is to boot and immediately set SELinux to enforcing mode.
Should you chose to change the default mode, you simply need to change that one line from “SELINUX=enforcing” to “SELINUX=permissive or “SELINUX=disabled” depending on your desired option.
Of course, I recommend enforcing as does the majority of the Linux community. After all, enforcing is the default option.
From memory, Ubuntu is one of a very few Linux distributions that actually doesnt use SElinux by default. That’s their prerogative, but if you care about security, I’d suggest using a vendor who has the same goals as you.
The other way we can change the SELinux mode is to use the “setenforce” command.
Firstly, you may be interested to know what your current mode is. Here we would use the “getenforce” command.
For example:
Although my default system mode is Enforcing, I have previously set it to permissive mode for some testing. You can see this with the below output.
[mac@rhodey ~]$ sudo getenforce Permissive [mac@rhodey ~]$
If I want to set SELinux back to Enforcing mode. I would run the following.
[mac@rhodey ~]$ sudo setenforce 1 [mac@rhodey ~]$ sudo getenforce Enforcing [mac@rhodey ~]$
Above we can see that SELinux has now been set back to enforcing mode, as well we have verified its new state.
A general rule of thumb to remember “setenforce” is “1” is for Enforcing, and “0” is for “Permissive”. This comes in very handy when troubleshooting a potential SELinux denial issue as you can quickly flick back between both modes.
Checking, Changing and Restoring SELinux contexts
Like normal, every day file permissions, like read, write and execute, SELinux has additional information which is important to use. This information relates to the provided SELinux policies that ship with your distribution.
As all Linux tools try to conform to standards across the board, the “-Z” flag has been used to show SELinux contents across the board.
For example:
To show the SELinux context of a file, you would use “ls -Z”
[mac@rhodey ~]$ touch /home/mac/myfile [mac@rhodey ~]$ ls -Z /home/mac/myfile -rw-rw-r--. mac mac unconfined_u:object_r:user_home_t:s0 /home/mac/myfile [mac@rhodey ~]$
[mac@rhodey ~]$ touch /tmp/mytmpfile [mac@rhodey ~]$ ls -Z /tmp/mytmpfile -rw-rw-r--. mac mac unconfined_u:object_r:user_tmp_t:s0 /tmp/mytmpfile [mac@rhodey ~]$
In the above two examples, you can see that although these files are created in the same manner, the default SELinux policy for parent folder is applied to the file.
The context is applied at the time of creation. If you move your /tmp/mytmpfile to your home directory, the context will not change.
In many cases, this is the perfect example of a context mismatch which is incorrect for the file or location being used.
You can rectify this type of issue by using the “restorecon” command.
For example:
[mac@rhodey ~]$ mv /tmp/mytmpfile /home/mac/ [mac@rhodey ~]$ ls -Z /home/mac/my* -rw-rw-r--. mac mac unconfined_u:object_r:user_home_t:s0 /home/mac/myfile -rw-rw-r--. mac mac unconfined_u:object_r:user_tmp_t:s0 /home/mac/mytmpfile [mac@rhodey ~]$ restorecon /home/mac/mytmpfile [mac@rhodey ~]$ ls -Z /home/mac/my* -rw-rw-r--. mac mac unconfined_u:object_r:user_home_t:s0 /home/mac/myfile -rw-rw-r--. mac mac unconfined_u:object_r:user_home_t:s0 /home/mac/mytmpfile [mac@rhodey ~]$
Above you can see how easily you can correct a fairly simple SELinux problem.
The majority of the times, your major SELinux issues will most likely be a simple context mismatch.
Creating your own SELinux policy
From time to time you will need to create your own policy. Particularly if you spend alot of time building custom apps to do weird and wonderful things.
Last week I had a genunine case of creating a SELinux policy for something I was working on. I followed my steps below for troubleshooting and identified that I had a genuine problem which needed rectifying.
By far the simplest way I have found to create a custom SELinux policy is to use the “audit2allow” command.
If you have managed to capture some logs from /var/log/audit/audit.log whilst your task is failing, you can turn those logs into an allow policy.
Please note: sometimes you won’t have any logs appearing. This may indicate an existing policy which is telling SELinux not to log a particular event, but still deny it.
You can re-enable all policy logging by issuing the following command.
[root@rhodey ~]# semodule -DB
What the above command does, is disables the “don’t audit” policy and rebuilds the policy data. This should now result in any and all denials being logged to /var/log/audit/audit.log.
What we need to do now is to capture some logs. Whilst running SELinux in permissive mode (setenforce 0) tail the /var/log/audit/audit.log file and re-perform your task which has previously failed.
Copy those logs into a new file. In this example, I called mine myselinuxlogs.txt
The contents of my file is as follows
type=USER_AVC msg=audit(1358202964.902:412): pid=563 uid=81 auid=4294967295 ses=4294967295 subj=system_u:system_r:system_dbusd_t:s0-s0:c0.c1023 msg='avc: denied { send_msg } for msgtype=method_return dest=:1.106 spid=548 tpid=2305 scontext=system_u:system_r:systemd_logind_t:s0 tcontext=system_u:system_r:udev_t:s0-s0:c0.c1023 tclass=dbus exe="/usr/bin/dbus-daemon" sauid=81 hostname=? addr=? terminal=?'
Now what we need to do is cat this file and pass it to “audit2allow”.
In this example, we will create a new SELinux policy called “my-test-policy”
[root@rhodey ~]# cat myselinuxlogs.txt | audit2allow -M my-test-policy ******************** IMPORTANT *********************** To make this policy package active, execute: semodule -i my-test-policy.pp [root@rhodey ~]#
The above command will create two files. my-test-policy.te and my-test-policy.pp.
You can open the my-test-policy.te file and you will see the actual SELinux policy it has generated from your log file.
Mine is as follows.
[root@rhodey ~]# cat my-test-policy.te module my-test-policy 1.0; require { type systemd_logind_t; type udev_t; class dbus send_msg; } #============= systemd_logind_t ============== allow systemd_logind_t udev_t:dbus send_msg; [root@rhodey ~]#
All we need to do now is install our new compiled module.
To do this, run the following, which was instructed above.
[root@rhodey ~]# semodule -i my-test-policy.pp
Monitoring and troubleshooting
Monitoring and troubleshooting SELinux can be a bit of a mixed bag of tricks if you are unfamiliar with how it functions.
The best piece of knowledge for troubleshooting would be knowing that everything gets logged to /var/log/audit/audit.log.
If I have an application which doesn’t seem to be working and I know I have SELinux enforcing, I follow these below steps to start testing if SELinux is actually the cause of the problem.
- Prove it fails:
Find a task that fails. This could be launching a service or even something simple like executing a script. - Confirm or Deny the problem is SELinux related
Here it is a simple case of running “setenforce 0” and then rerunning step 1. If your task now works, you have proven you have either a SELinux permission or policy issue. - Use a bit of common sense.
If you have just been editing some conf files, lets say for example you just created a new config file for a particular service. Perhaps the permissions of your new file are incorrect. Perhaps you need to run “restoreon” on your new files. - Watch the log file to see what is going on.
By running “tail -f /var/log/audit/audit.log” in a shell whilst you rerun your task, you will be able to see the output being generated from your denial. It may help to point you in the direction of where the problem may lie. - Fix the problem
I can’t stress how frustrating this topic is. Fixing the problem is what we all do in our professions. Leaving SELinux in either Permissive or Disabled mode, is not fixing the problem. It is simply ignoring the situation.
If you need to create your own SELinux policy to resolve the issue, then create a new policy. That’s the real way to do things.