Security Thinkstock

Don’t Disable SELinux

Developers often recommend disabling security like SELinux support to get software to work. Not a good idea.

I used to do it. Most recommendations on sites like StackOverflow and Reddit say to do it in order to get software to work. And yes, disabling security features—like turning off SELinux—will allow software to run. All the same, don’t do it!

For those who don’t use Linux, SELinux is a security enhancement to it that supports mandatory access controls. SELinux support can take the form of any number of Linux distributions, like Red Hat Enterprise Linux (RHEL). It is also available in many embedded Linux incarnations.

Nor is SELinux the only security option other than the standard user/group file permission support that is available with all Linux implementations. There is also the POSIX access control list (ACL) support, but this is discretionary access control (DAC) versus SElinux’s mandatory access control (MAC). Another MAC available with Suse and Ubuntu Linux is AppArmor. Embedded Linux implementations built with Yocto can include a MAC option.

Only one security system can be included in a system, although they coexist with the standard Linux file permission scheme, and Linux has pluggable support for security to allow different systems to be employed. Also, SELinux extends past file permissions to included resources like network ports.

SELinux actually provides a mix of Role-Based Access Control (RBAC), Type Enforcement (TE), and optionally, Multi-Level Security (MLS). Each entity in the system is labeled with an SELinux context of the form user:role:type:level. A typical directory listing of file contexts looks like:

# ls -Z Wong1*
-rw-------. qemu qemu system_u:object_r:virt_content_t:s0 Wong1-base.qcow2
-rw-------. qemu qemu system_u:object_r:svirt_image_t:s0:c345,c401 Wong1-centos7.qcow2
-rw-------. qemu qemu system_u:object_r:svirt_image_t:s0:c345,c401 Wong1-S.qcow2
-rw-------. qemu qemu system_u:object_r:svirt_image_t:s0:c345,c401 Wong1-T.qcow2

This is an example of some files in image directory for the libvirt virtual machine support. The QCOW2 files are disk images. Their type is svirt_image_t and virt_content_t. The former is a read/write file, while the latter is read-only. QCOW2 images can be based on other images, as is the case in this example. The Wong1-centos7.qcow2 file is based on the Wong1-base.qcow2 file. The latter should not be changed, since it may also be shared with other files like the former. The Wong1-centos7.qcow2 file will only be used by one virtual machine.

Essentially, the base file was created first with a Linux installation. At that point, the type was svirt_image. It was changed to virt_content_t when Wong1-centos7.qcow2 was created and used in a virtual machine. Subsequent changes to the image file essentially replace those in the base file. It is a way to quickly get a new virtual machine up and running based on a prior installation.

For this security discussion, the Wong1-base.qcow2 file is now read-only because it is flagged as virt_content_t, but the type does more than that. The file is read-only and usable only by the libvirt virtual machine support. Likewise, the SELinux system overrides the Linux file system attributes that were -rw-------. or a 0600 bit mask.

The virt_content_t and svirt_image_t context types are just two associated with the SELinux profiles defined for the virtual machine support. There are similar definitions for all applications. For example, the Apache web server, httpd, uses types such as public_content_rw_t for shared files and httpd_sys_script_exec_t to allow CGI scripts to run.

The plethora of types, not to mention the user and object level context information we have not discussed, is where many users become confused or frustrated when dealing with SELinux because of the added complexity. The basic Linux permission system simply had applications running with a user and group associated with them, and these applications were able to access any file that had matching attributes. SELinux provide a more fine-grained approach that essentially isolates a group of resources like files or directories for use with a particular application.

The advantage of SELinux is the ability to protect applications and content from others in the system. Compromising one application does not necessarily compromise the entire system.

Changing a file’s context is done using chcon, versus changing a file’s permissions using chmod or chown. SELinux can also map particular file name patterns to particular contexts using the semanage and restorecon programs. For example:

# semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
# restorecon -R -v /web

In this case, semanage saves a file context pattern for all files and directories in the /web directory. The restorecon program then changes each file’s type to httpd_sys_content_t. 

Many tips about SELinux that don’t tell you to disable it, will present this approach. One tool often overlooked is matchpathcon. This actually checks the current context patterns for the Apache web server’s default directory.

# matchpathcon -V /var/www/html/*

SELinux profiles for an application usually includes these types of definitions for a typical installation. The Apache web server is a good example of this. Normally there is a standard file and directory structure. Accidently creating or editing files and directories can cause the contexts to be incorrect, preventing the application from running as desired. Using restorecon typically fixes these problems.

Likewise, many applications have SELinux booleans that control global attributes of the system. For example, it is possible to limit TCP port access to specific scripts. This would be the correct way of managing this access to prevent a script from using a port needed by another application. Letting scripts using any port can be done using:

setsebool -P httpd_can_network_connect 1

The httpd_can_network_connect variable allows this to happen when it is set to 1 (True). The -P option makes the change permanent—otherwise, the variable would be set to 0 (False) on a reboot. Again, the level of complexity, even for these booleans, can be high as the Apache profile alone has dozens. Getting a list of the current settings for the web server can be done using:

getsebool -a | grep httpd

Getting a list of file types, users, and objects is done using seinfo that is part of the setools-console package for RHEL. Getting a list of types associated with the Samba file server can be done using:

seinfo -t | grep samba

Unfortunately, the descriptions for the types and booleans requires scanning the man pages or other documentation. Likewise, determining which item will address a particular situation may also require reading these in more detail. Still, the names themselves often indicate their function sufficiently to deduce their use.

Thus far we have looked at using SELinux with existing policies, albeit at a very cursory level. For embedded developers, this may be sufficient when using existing applications like the Samba file server or the Apache web server. Developers creating new applications will likely need to develop their own policy modules. That is a much different task, but not necessarily a complicated one, since it is a matter of defining rules about what resources the application can utilize. A simple policy looks like:

policy_module(localpolicy, 1.0)
  type user_t;
  type var_log_t;
allow user_t var_log_t:dir { getattr search open read };

The backtick (‘ ) in gen_require denotes the start of a block and the regular tick (') marks its end. This example allows the getattr, search, open, and read operations to be used with file and directory contents labeled with user_t and var_log_t.

The audit2allow program is typically recommended to generate policies to add to a system, so as to enable resources to be used where an existing configuration is not working. The SELinux audit log contains infractions that can be filtered and run through the audit2allow program to create a policy the will allow those operations to proceed.

The challenge with using this approach is that a proper policy will need to enable a variety of actions, and most applications abort when something goes wrong. This requires multiple iterations to allow all the resources to be accessed for the application to work properly. For example, web-based CGI script  may need to use specific ports, files, and directories to run. The script would abort if SELinux is running in enforcing mode versus permissive mode. The latter allows infractions to occur but logs them. The trick is to run the application while in permissive mode and record the problems that are then run through audit2allow. The resulting policy can then be tested with SELinux running in enforcing mode.

Note that policies generated by audit2allow are functionally the same as a policy created for an application, but they serve different purposes. Ones created specifically for an application have usually been designed for a recommended configuration. The audit2allow policies are ones needed to allow a specific configuration to work.

Working with security support like SELinux and AppArmor can be daunting, but the concepts and implementation are actually quite logical. So please avoid:

setenforce 0

or disabling SELinux altogether. Your system will be more secure in the long run. Check out the SELinux website, CentOS SELinux How To, or An Introduction to SELinux on CentOS 7 for a more in-depth look at SELinux. CentOS is a free version of RHEL.

Hide comments


  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.