80:20:SELinux
What is SELinux
SELinux implements what Information Security folks call Mandatory Access Control (MAC) on top of traditional Unix access control (User:Group:Other permissions). Traditional Unix access control (called discretionary access control or DAC for short) considers all processes with equivalent user:group ownership as equivalent and grants all such processes access to the same set of resources. But why should the web-server have root execution privileges on the passwd
command? The vast majority of hypothetical scenarios where a web-server is changing user passwords are nefarious. The addition of MAC security on top of traditional methods provides a mechanism which can be used to deny access to all resources not strictly required.
What is this Article
SELinux is complex, but digestible. This text seeks to include all the information required to develop the capacity to understand and manipulate the Targeted Policy, included by default in a CentOS 8 system. Information not directly related to that task will be included to expose the reader to the terminology used in related documentation.
What is in this Article
The exploration of background information begins with an architectural overview of SELinux, a high level description of some of the composite components and their behaviors. After that, it will be necessary to describe how SELinux labels the “objects” of access control, understanding these labels, which are called contexts, is crucial to administrative tasks. The policy comes next. Different security models are defined in the policy, and an understanding of how it secures the system is crucial.
All of this theoretical understanding will be put to use describing the tools of the trade, the location of access control logs, and utilities which display and change context information and set policy behavior. The tools section of this article will include everything necessary to assign resources to the proper domains and authorize confined processes resources they need in a CentOS 8 system running the default targeted policy in enforcing mode.
Background
System Components
SELinux uses a kernel module, policy, and labeled file system to provide access control. In a nutshell, the policy is used to generate labels for file system objects, Linux users, and processes which SELinux calls contexts. These contexts categorize the “objects” of access control and are used by the kernel module during operation as the means of identification.
A little context on contexts and their content :)
Context context :/
Access decisions are made on computer resources. However, these resources are not identified using the usual identifiers (file path, UID, and PID). Instead the security context is used. For a file system object this context is written in the extended attributes and for a process the security context (also called the domain of a process) is by default inherited from its parent process, but often policy rules exist which dictate a new security context based on the type of the executable exec()
'ed.
Context content :|
The context takes the form:
<user>:<role>:<type>:<range>
Convention dictates that the user, role, and type fields have the respective suffixes u, _r, _t. Although ignoring this convention is not necessarily system breaking it would greatly impact the readability of the contexts and policy (read: ignoring this convention is probably not wise_).
example_user_u:example_role_r:example_type_t:s0
Context Fields
User
The user refers to the SELinux user. This field is useful for system auditing as it produces an immutable identifier that can be used used by administrators to identify the source of a breach. In Role based access control schemes SELinux users are allowed to take on a certain number of roles, thus allowing the creation of different privilege classes of users.
Roles
Roles in SELinux are not surprisingly also used in Role based access control schemes (RBAC). According to the Gentoo Wiki (an excellent resource) RBAC is used:
To provide segregation of duties and privileges based on the least privilege model, many organizations use a role-based implementation for security and privileges.
In RBAC the user field of the context determines the allowable roles the process can acquire. These roles allow for permissions on different domains.
Types
The type field of the SElinux security policy does the heavy lifting when it comes to access control in the Centos 8 Targeted Policy. Type information is used as the identification which matches processes and objects to the appropriate subject access object rules of the policy. As such documentation will often contract the domain of a process (another word for a process's security context) to just the type field.
Range
The range field is actually composed of two ranges, the sensitivity and category ranges. This field is not typically used in the targeted policy. The idea is that this field defines the range of sensitivities/categories a domain/object has access to giving a granular access control scheme.
The first part of the range field is the sensitivity, and following that is the category.
s0-s0:c0.c255
If the upper portion of the range is the same as the lower, it may be omitted.
s0:c0.c255
The category range c0.c255
defines an ordered set between category 0 and 255 inclusive. If instead the author of the context wanted to specify specific categories a comma separated list would work.
s0-s0:c0,c5,c10
Enlightened context authors see the inter-connectivity of the everything in the universe and therefore the ultimate futility of boxing off components into categories. As a result you might be exposed to range fields with no category information.
s0
Policy
The policy is a binary list of rules specifying if domains have permissions on objects. The domains and objects are referenced by context components only in these rules, file-paths or PIDs are not considered.
In the default Centos 8 Targeted Policy all Linux users are mapped to the unconfined context as well as many user processes which run without root permissions or do not listen on a network port.
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Unconfined processes will not receive access restrictions from SELinux (although they still will be subject to traditional DAC restrictions), spitting in the face of SELinux's deny by default implementation. One is left to wonder whether the reasoning for omitting the normally tight security provided by Mandatory access controls on machines running CentOS 8 is the policy authors thought it was too annoying to write a general purpose policy or if it is because the users found it too annoying to live with.
Confined processes are not exempt from the default to deny lifestyle of SELinux, so rest easy. These processes are only allowed permissions on objects where a specific subject access rule exists. These rules take the form:
allow <subject> <target>: <class> { <permission> }
The allow
keyword declares that the “access vector” described by the following parameters is permitted. The subject
parameter is the domain (process) requesting permission. The target
is the object the subject
is attempting to 'act' on. The class
further describes the target
. A target defined by its context can be further characterized via this field. Example classes are file
, dir
, and socket
. Finally the permission
describes what 'act' is being authorized.
Tools
Stage set: A lone system administrator pulls at his hair, late in the night in front of a glowing screen. Its been 8 hours. Teeth gnashing, he forces his hands back onto the keyboard to attempt again to diagnose why his web server keeps throwing 403 errors (this is a true story by the way). The python environment is properly configured, as is the Virtual Host declaring the site root mounts the WSGI script application, the application works when it uses its own development server, and all the httpd/error_log has to say about the situation is Permission Denied. How did this administrator eventually solve the issue? He realized that SELinux was probably the cause, he used setenforce 0
to change SELinux runtime behavior so that the SELinux kernel module did not actually block system calls but still logged policy violations. This confirmed that the problem was being caused by a policy violation. He looked up if there was a man page for httpd SELinux (there often is) with apropos httpd
, finding that there was one he used man 8 httpd_selinux
to find which type to assign to what files. With the correct type information in hand our hero used semanage fcontext -a -t httpd_sys_script_exec_t /var/www/wsgi-scripts(/.*)?
.
So you get that SELinux implements mandatory access controls on a Linux system by labeling the file system using a policy, which is composed of rules which restrain, when they specify subject
has permission to preform attempted action on target
object, the kernel modules default behavior of blocking all system calls. In order to actually put that knowledge to use an administrator needs to know:1. How to view policy decisions.2. Get context information for relevant files, directories, and users.3. Change context information or set booleans to set SELinux runtime behavior.
NOTE: When debugging, it can be tempting to turn off SELinux to see if that solves the problem. DO NOT DO THIS! Newly created files will not be given a security context while SELinux is off. Instead putting SELinux into permissive mode will stop SELinux from actually enforcing access control. This has the added benefit of still producing audit messages, which can be used to figure out the cause of perplexing behaviors. Use the SELINUX=disabled|enforcing|permissive
variable found in the /etc/selinux/config
and reboot for persistent changes. The setenforce
command can be used for non-persistent changes to the operation mode of SELinux, setenforce 0
to start permissive mode and setenforce 1
to enter enforcing mode.
Often the first action that must be taken by the administrator working with opaque access control errors is viewing the audit logs (on CentOS at /var/log/audit/audit.log
). The Linux Audit system is built to record everything that everyone did on a machine for security purposes. To filter the audit logs for just the SELinux related entries use a pager and search for AVC
(for the Access Vector Cache). These audit reports will describe the source
domain involved in the violation, the target
object, relevant context information, and the requested permission
. This infomation can be very useful. With it one can figure out which documentation will explain how to authorize access. Use apropos <process command>
to see if any SELinux related documentation is already installed on your system.
It might also be useful to query specific files, directories, processes, or users to get their context information. Convention dictates that a command switch used to display security contexts is -Z.
ls -Z
display file context labelps -Z
display process (djust change the object that one whiches to authorize some confined domain access toomain) context labelid -Z
displays the shell's user context label
When enough information is gathered and if the administrator decides to make a change to the context label for some object there are some considerations. Firstly,the user and role fields are primarily for use in RBAC schemes to create a separation of duties which provides the least privileges necessary. An administer working with the default Targeted Policy will not have to worry about that as he or she will likely be an unconfined user. The same goes for the range field. So generally if an admin wants to allow some source
permission on some target
object it is sufficient to change the type field in the context label of the target
object. SELinux related documentation will likely list the different types and their associated permissions.
After relevant documentation is queried, changes can be made to the context label of files or recursively for directories with the command:
semanage fcontext -a -t <desired_new_type_t> <target_object>
Pattern matching can be used with globbing to match multiple objects with one rule.
The updated policy is not applied to the file system without specifically calling for a relabel. The restorecon -R </dir/for/relabel>
can be used to relabel a particular part of the file system live. One can also touch /.autorelabel
to force a complete relabeling of the file system at boot.
Helpful Resources
This article was made possible by some of the awesome documentation found on the web. Anybody wanting to learn more about SELinux was not be remiss using these resources to learn some more.
The MAN Pages
Obviously, rock solid source of information. The selinux-policy-doc
package provides a bunch of service specific SELinux man pages. With selinux-policy-doc
installed, use man -k <command>
or apropos <command>
. The appropriate page will have the _selinux suffix.
Gentoo Wiki
Awesome awesome awesome Goldilocks resource. Not overly simplistic, but not impenetrably dense. The concept section is quite good.
SELinux Wiki
Maybe it is not a surpise that the project Wiki is a good resource. However, the author of this very article did not know of the existence of this resource for too long.
RHEL 8 Documentation
Awesome series, does a great job of holding the readers hand tight while stepping through a tour of SELinux.