Last time, I introduced you to SELinux: what it is, what it can do, and really why you need it (or a system like it). It is especially important with reported (and fixed) security vulnerabilities on the rise, and each year brings more reports, and more updates for end-users to install. This data tells us that we are in greater need of proactive security measures now than we ever were before. And this is where software like SELinux fits in.
There is a lot to SELinux, and we're only going to touch on SELinux contexts and labels. Suffice it to say, SELinux policies contain various rules that allow interaction between different contexts. Contexts are ports, processes, files, directories, and so on. Instead of getting overwhelmed with the technical concepts of SELinux, we'll instead look at the practical side of using SELinux so that it doesn't seem quite as daunting.
The first thing to do is determine what mode SELinux is running in:
The getenforce command tells us what mode SELinux is in. The possible modes are Enforcing, Permissive, or Disabled. Enforcing means that SELinux will report access violations and deny the attempt, Permissive tells SELinux to report the violation but allow it, and Disabled completely turns SELinux off.
Ideally, if you are unprepared to run SELinux in Enforcing mode, it should be in Permissive mode.
This can be set at boot by editing (on Red Hat Enterprise Linux and Fedora) the /etc/sysconfig/selinux file and setting the SELINUX option:
This will ensure it persists across reboot. SELinux can transition from Enforcing to Permissive easily using the setenforce command. Providing setenforce with a "0" argument will put the system in Permissive mode, a "1" will set it to Enforcing. To transition to or from Disabled mode, you need to reboot after making the appropriate changes to the sysconfig file. Using setenforce can be a great way of troubleshooting problems; if the problem goes away after setting the system to Permissive mode then you know it is SELinux.
If not, then it is something else.
# setenforce 0
To view the contexts that a process is running with, add the Z option to ps:
# ps auxZ | grep httpd
system_u:system_r:httpd_t:s0 apache 30544 0.0 0.0 305612 6688 ? S Mar30 0:00 /usr/sbin/httpd
This tells us that the httpd process is using the httpd_t type, the system_r role, and the system_u user. More often than not, it is the httpd_t type you would be interested in.
The Z option is also used with other commands, such as ls, cp, id, and others. For instance, to view your security context:
# id -Z
Or to view the security context associated with a file:
# ls -lZ /var/www/html/index.html
-rw-r—r—. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html
Again, probably the most useful bit of information here is the type, in this case it is httpd_sys_content_t.
As an example of how to quickly change the policy, assume that you do not put your websites in /var/www/, but rather use /srv/www/foo.com/html/ for your site's document root. You can configure Apache to use these directories as the DocumentRoot for various websites, but if you were to visit them, Apache would return an error because SELinux would disallow access. SELinux knows nothing about allowing Apache to these directories as of yet.
To determine what type a file needs to have in order for Apache to access it, the above ls command tells us that the type we want is probably httpd_sys_content_t; after all, Apache by default serves files from /var/www/html/. Another, probably better, way is to use the semanage tool.
This tool is used to show, and change, defined SELinux policy. We could also do:
# semanage fcontext -l | grep '/var/www'
/var/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
This command tells semanage to list all fcontext entries (file contexts), and we hand that output to grep to search for and display '/var/www'. For brevity, the whole output is not shown, but the above confirms that /var/www/* has the httpd_sys_content_t type. So what we need to do is tell SELinux to give this same type to /srv/www/foo.com/html/*, so that Apache can serve up those files.
This can be done by using semanage to add a new context:
# semanage fcontext -a -t httpd_sys_content_t '/srv/www(/.*)?'
# semanage fcontext -l | grep '/srv/www'
/srv/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
# restorecon -Rv /srv/www
The SELinux policies here use regular expressions, so the above tells semanage to add (-a) a new fcontext with the type (-t) httpd_sys_content_t, and targets /srv/www itself and any sub-directories and files. We use semanage to list the fcontexts and search for any '/srv/www' entries, to verify it is in place, and then use restorecon to re-label and set the appropriate security context on the /srv/www directory and any sub-directories and files.
At this point, Apache will serve content from that directory if configured to do so, because Apache has the right to read httpd_sys_content_t files and /srv/www/ will now be labeled correctly.
The restorecon tool is used to set default contexts on files and directories, according to policy. You will become very familiar with this tool because it is used very often. For instance, if you move a file from a home directory to this web root, it will not immediately gain the appropriate security context because the mv command retains the existing context (cp will make a new context because it is making a new file). For instance:
% echo "my file" >file.html
% ls -Z file.html
-rw-rw-r—. vdanen vdanen unconfined_u:object_r:user_home_t:s0 file.html
% mv file.html /srv/www/foo.com/html/
% ls -Z /srv/www/foo.com/html/
-rw-rw-r—. vdanen vdanen unconfined_u:object_r:user_home_t:s0 file.html
Apache is not, by default, allowed to serve up user_home_t files, so any attempt to display this file via Apache will fail with denied access. restorecon is required to re-label the file so Apache can access it:
# restorecon -v /srv/www/foo.com/html/file.html
restorecon reset /srv/www/foo.com/html/file.html context unconfined_u:object_r:user_home_t:s0->system_u:object_r:httpd_sys_content_t:s0
Now the security context of the file is correct.
Similarly, when going from Disabled mode to Permissive or Enforcing mode, SELinux will have to re-label the entire filesystem (effectively running "estorecon /) because contexts are not set at all when SELinux is disabled.
Once you wrap your head around these basics of SELinux, all of a sudden it is no more difficult to use than manipulating iptables firewall rules. Just as you would adjust your firewall to allow access to a new service, you adjust SELinux file contexts to allow applications and services to access them. Yes, it does require a little more work to set up, initially, but the security benefits are really quite useful, especially considering that the bulk of this kind of manipulation will only happen when initially setting up a system or adding new services. And getting into the habit of running restorecon on new files and directories as they are created isn't any more difficult than using ls on them to double-check their permissions.
The next and final tip on SELinux will introduce us to SELinux logging, to detect access violations, and to some other basic SELinux commands.
Vincent Danen works on the Red Hat Security Response Team and lives in Canada. He has been writing about and developing on Linux for over 10 years and is a veteran Mac user.