SELinux Concepts
Security-Enhanced Linux (SELinux) is a mandatory access control (MAC) system that enhances Linux security. "Mandatory" means access control is strictly enforced by predefined policy rules—users and processes cannot modify these rules at will, ensuring security is not left to individual discretion. SELinux is available in major distributions, including Amazon Linux 2023 (AL2023) and Bottlerocket. This post is the part 1 of a series on SELinux.
Labels and Contexts
SELinux labels every file and process using a quadruple: (user:role:type:level). In SELinux, labels are the only input for access control decisions. It does not matter which Linux user owns a file or started a process—only the labels matter. The terms "label" and "context" are often used interchangeably. Many Linux commands, such as ls
, ps
, and id
, support the -Z
option to display SELinux contexts:
1bash-5.2# ps -Z 52482
2LABEL PID TTY STAT TIME COMMAND
3system_u:system_r:container_t:s0 52482 ? Ss 0:00 sh -c yum -y -q ins
- SELinux user:
system_u
(distinct from the Linux user) - SELinux role:
system_r
- SELinux type:
container_t
- SELinux level:
s0
(can also include level ranges and categories, e.g.,s0-s2:c0.c1023
)
In SELinux naming conventions:
- Users, roles, and types have suffixes
_u
,_r
, and_t
respectively - Sensitivity levels use the prefix
s
, while categories usec
Type
The type is the core of SELinux. For processes, the type defines what a process can do and is why SELinux is often called a "Type Enforcement" (TE) security model. The same program can run under different types depending on how it is started. For example, when launching httpd in AL2023:
- Launch it with systemd (
sudo systemctl start httpd
): the httpd process hassystem_u:system_r:httpd_t:s0
- Launch it directly (
sudo /usr/sbin/httpd
): the httpd process hasunconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
For processes, "type" and "domain" are interchangeable terms.
Users and Roles
SELinux supports role-based access control (RBAC) using SELinux users and roles. The relationship between users, roles, and types can be summarized as:
For example, a SELinux policy could enforce that only certain SELinux users can execute a program by:
- Enforcing a program to be executed as certain types, e.g.,
hello_t
- Associating
hello_t
tohello_r
- Associating
se_foo_u
tohello_r
, andse_bar_u
to a role other thanhello_r
Then, any Linux user that is mapped to se_bar_u
cannot run the program. Learn more about roles at The purpose of SELinux roles.
Sensitivity (MLS - Multi-Level Security)
Sensitivity labels are optional in SELinux and are part of Multi-Level Security (MLS). You can check if MLS is enabled with:
1bash-5.2# sestatus | grep MLS
2Policy MLS status: enabled
MLS implements hierarchical security levels based on the Bell-LaPadula model, a security model characterized by "no read up, no write down": a process cannot read anything with a higher confidentiality level nor write/communicate to any resource with a lower confidentiality level.
Sensitivity levels are numbered from s0
(lowest) to s15
(highest) by default. A process or file can have a single level: s0
, or A range of levels: s0-s3
(clearance from s0 to s3).
MLS is commonly used in government and military environments where information classification is critical. Most general-purpose Linux distributions run with MLS disabled or use only s0
, as the strict access controls can interfere with normal operations.
Categories (MCS - Multi-Category Security)
Categories work like tags for processes and files, providing compartmentalization within the same sensitivity level. Unlike MLS's hierarchical levels, categories are non-hierarchical—they provide lateral separation rather than vertical classification. Categories are numbered from c0
to c1023
and can be combined in ranges (e.g., c0.c5
(categories 0 through 5)) or sets (e.g., c0,c3,c7
(specific categories 0, 3, and 7)):
A process can only access resources that share at least one category with it, or resources with no categories at all. Docker and Kubernetes use MCS categories to isolate containers. Each container gets a pair of categories and containers in the same K8s pod have the same pair. By convention, container runtimes use at least two categories per tenant to reduce the probability of category collision in multi-tenant environments. See go-selinux for implementation details.
Class and Permission
A class is a named collection of permissions. For example:
- The class
process
has permissions:fork
,transition
,sigchld
,sigkill
, etc. It looks like permissions map one-to-one to syscalls, but that's not the case - The class
service
has permissions:start
,stop
,status
,reload
,enable
,disable
Each class can have a maximum of 32 permissions since it is stored as a 32-bit field in the kernel.
Subjects, Objects, and Actions
SELinux is fundamentally about answering questions of the form "Can a subject perform an action on an object?". Often, the subject is a process, the object is a process or file, and the action is a combination of class and permission. For example, an action file:read
means the permission read
in the class file
.
Type transition
Type transition automatically assigns security contexts to newly created objects based on defined rules.
The type transition rule specifies the labeling and object creation allowed between the source_type and target_type.
For example, (typetransition init_t os_t process system_t)
says PID 1 starts most daemons as "system_t".
Policy
SELinux policy is a collection of rules that defines "can a subject perform an action on an object?". The compiled policy file is stored at /etc/selinux
:
1ls -lh /etc/selinux/targeted/policy/policy.33
2-rw-r--r--. 1 root root 3.5M Jan 22 01:48 /etc/selinux/targeted/policy/policy.33
Policies can be thought of as a table (source: SELinux from the inside out):
Access Vector Cache (AVC)
SELinux caches access control decisions in the AVC. Think of SELinux as a client-server model, where AVC is the cache on the server.
Permission denies caused by SELinux can be found by journalctl -k | grep -i avc
.
Common Intermediate Language (CIL)
Common Intermediate Language is a human-readable policy language that sits between high-level policy languages (such as the reference language) and the low-level kernel policy representation. Bottlerocket implements SELinux using CIL only.