Many of us got used to the simple owner, group, and other model of Unix security so long ago that we were somewhat taken back when the setfacl and getfacl commands were introduced and added complexity to file permissions. All of a sudden, users and groups could be assigned access privileges separately from these three groupings and we had to pay attention to + signs at the ends of our permissions matrices that reminded us that additional access permissions were in effect.
Today, most Linux systems are implementing SELinux -- a far-reaching security enhancement that changes the character of system security, but requires that we deal with some additional complexity in managing our systems.
In last week's post, I supported the Linux hardening recommendation that SELinux be enabled. Today, we'll look more closely at what that means and examine some commands that might help you get more comfortable with this new security model.
To begin with, SELinux is an example of "mandatory access control" -- yes, another contender for the acronym "MAC". Exactly what this term is meant to convey centers on the notion of who or what controls access to files. In the traditional access control scheme -- discretionary (i.e., you get to choose) access control, users can pretty much set the security context for their files. They can set permissions on all of their directories to 777 if they are so inclined or set permissions on all of their files to 666 and their scripts to 777. Sure, root can check and change permissions, but users can change them back. That's sort of one of the "constitutional rights" of being a Unix user -- you get to control the access rights to files that belong to you. Given this, users can set overly permissive settings on their files -- something most sysadmins would prefer to constrain. SELinux provides some safeguards that can protect users' files even when your users are careless.
Traditional Unix security uses discretionary access control. The problem is that discretionary access control leaves too much control in the hands of end users and that it isn't fine grained enough to provide for more complicated permissions scenarios.
With mandatory (required) access control, even a user opening up all of his files and directories to world access does not mean that their files are wide open. On systems which enforce mandatory access control, the operating system constrains access in ways that override what users can do. A given application might not have the ability to read files even when permissions are left wide open. Instead, the operating system under MAC control will check each user's classification and category and then compare those to the security label of whatever they are trying to access.
Why is this important? One reason is because a rogue process on your system could find itself very limited with respect to the files that it can access. Even a process that is running under your user identity might not be able to access your files. That's a huge jump forward for Linux. In fact, it could mean that you will finally have an opportunity to be truly proactive with respect to security. Instead of waiting for vulnerabilities to be discovered and then patched, you might protect system services by defining up front the limited ways in which they can be used -- ways that probably won't include the actions that various exploits would take to break in or steal data.
Imagine, if you will, adding a back door to your home that only you, your family and your dog are able to use. SELinux uses security contexts to further constrain who gets access to what. If the security context for your back door is "family only" and that context is enforced, no amount of crow bars, lock picks or family members forgetting to lock the door behind themselves would matter.
Yet you, as a Linux systems administrator, could change the security policy that is being enforced as needed and without rebooting your server. In fact, you would have the ability to write policies to your liking and ensure that any type of service is secured.
SELinux operates in one of three modes. Which is in effect when a system is installed will depend on the distribution and release. The modes are:
- enforcing -- SELinux is operating
- permissive -- SELinux is active, but only displaying warnings
- disabled -- SELinux is turned off entirely
You can run the sestatus or the getenforce command to see which mode your system is running in.
$ /usr/sbin/sestatus SELinux status: enabled $ /usr/sbin/getenforce Enforcing
As root, you might see more information:
# 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
If SELinux is disabled or permissive, you can move to enabled by changing the setting in your /etc/sysconfig/selinux file to enabled and rebooting. If you've been running with SELinux disabled and want to turn it on, you might consider first spending time in permissive mode so that you can view warnings about any problems you might run into before fully making the transition.
Rebooting when you first enable SELinux will take a little extra time while and you can expect to see a message like this when you reboot.
*** Warning -- SELinux targeted policy relabel is required. *** Relabelling could take a very long time, depending on the *** system size and speed of hard drives.
For me, this process took under 2 minutes. That's very long for a Linux reboot, but very quick for a file system
Once SELinux is running, you can temporarily change the mode in which SELinux is operating with the setenforce command. With an argument of 0, setenforce puts SELinux into permissive mode. With an argument of 1, it puts it back into enforcing mode.
# setenforce 0 # getenforce permissive # setenforce 1 # getenforce Enforcing
When you're working on a Linux system with SELinux in enforcing mode, things might appear to be normal, but some minor changes in the commands you use and the output you see will reveal that there's a lot more going on.
Add a capital "Z" to your ps commands and you will see the contexts in which processes are running. Notice the user (*_u), role (*_r) and type (*_t) indicators that have been added to each process line.
# ps -auxZ | grep httpd LABEL UID PID PPID C STIME TTY TIME CMD system_u:system_r:init_t:s0 root 1 0 0 14:06 ? 00:00:01 /usr/lib/systemd/systemd system_u:system_r:kernel_t:s0 root 2 0 0 14:06 ? 00:00:00 [kthreadd] system_u:system_r:kernel_t:s0 root 3 2 0 14:06 ? 00:00:00 [ksoftirqd/0] system_u:system_r:kernel_t:s0 root 5 2 0 14:06 ? 00:00:00 [kworker/0:0H] ... system_u:system_r:httpd_t:s0 apache 772 765 0 14:06 ? 00:00:00 /usr/sbin/httpd -k start system_u:system_r:httpd_t:s0 apache 773 765 0 14:06 ? 00:00:00 /usr/sbin/httpd -k start system_u:system_r:httpd_t:s0 apache 774 765 0 14:06 ? 00:00:00 /usr/sbin/httpd -k start ... unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 shs 1032 1008 0 14:10 ? 00:00:00 gnome-session
To see your account's security context, use the id -Z command:
$ id -Z unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Look at your files with by adding a -Z to your options and you will see similar indicators. Notice how, in the first line of the output, the type has been identified as user_home_dir_t and, in some of the subsequent lines, the files are of type user_home_t.
# ls -laZ | head -6 drwx------. shs shs unconfined_u:object_r:user_home_dir_t:s0 . drwxr-xr-x. root root system_u:object_r:home_root_t:s0 .. -rw-------. shs shs unconfined_u:object_r:user_home_t:s0 .bash_history -rw-r--r--. shs shs unconfined_u:object_r:user_home_t:s0 .bash_logout -rw-r--r--. shs shs unconfined_u:object_r:user_home_t:s0 .bash_profile -rw-r--r--. shs shs unconfined_u:object_r:user_home_t:s0 .bashrc
On this Fedora 17 system, each user is mapped to an SELinux user login by default. The user mapping can be viewed with the semanage login -l command.
# semanage login -l Login Name SELinux User MLS/MCS Range __default__ unconfined_u s0-s0:c0.c1023 root unconfined_u s0-s0:c0.c1023 system_u system_u s0-s0:c0.c1023
SELinux might disallow access to files if your files aren't in the expected location, but you can use semanage commands to make corrections.
For example, an apache process would not be allowed to read files outside of the default DocumentRoot unless you specifically adjusted the context -- this is good! If you locate your files outside of this location, you will need to run some commands to adjust.
If you try to share files (outside of home directories) using Samba, the files may not be viewable even when the shared directories are successfully mounted.
SELinux requires the files to be labelled with an attribute that further defines their type. For a Samba share (other than home directories), you should use the label samba_share_t. In the following commands, we label the directory with the chcon (change security context) command, use the semanage command to set the context for the files and make the change permanent, and run a restorecon command to apply the changes to all files and subdirectories.
# chcon -R -t samba_share_t /data/share # semanage fcontext -a -t samba_share_t '/data/share(/.*)' # restorecon -R -v /data/share
SELinux places new constraints on how files are accessed on Linux systems. As a new security mechanism, it's a lot to absorb and it adds a good deal of complexity to our systems. Even so, the security that it provides above and beyond what's been available in the past makes it well worth learning and using.