Skip to content

SELinux security

With the arrival of kernel version 2.6, a new security system was introduced to provide a security mechanism to support access control security policies.

This system is called SELinux (Security Enhanced Linux) and was created by the NSA (National Security Administration) to implement a robust Mandatory Access Control (MAC) architecture in the Linux kernel subsystems.

If, throughout your career, you have either disabled or ignored SELinux, this document will be a good introduction to this system. SELinux works to limit privileges or remove the risks associated with compromising a program or daemon.

Before starting, you should know that SELinux is mainly intended for RHEL distributions, although it is possible to implement it on other distributions like Debian (but good luck!). The distributions of the Debian family generally integrate the AppArmor system, which works differently from SELinux.


SELinux (Security Enhanced Linux) is a Mandatory Access Control system.

Before the appearance of MAC systems, standard access management security was based on DAC (Discretionary Access Control) systems. An application, or a daemon, operated with UID or SUID (Set Owner User Id) rights, which made it possible to evaluate permissions (on files, sockets, and other processes...) according to this user. This operation does not sufficiently limit the rights of a program that is corrupted, potentially allowing it to access the subsystems of the operating system.

A MAC system reinforces the separation of confidentiality and integrity information in the system to achieve a containment system. The containment system is independent of the traditional rights system and there is no notion of a superuser.

With each system call, the kernel queries SELinux to see if it allows the action to be performed.


SELinux uses a set of rules (policies) for this. A set of two standard rule sets (targeted and strict) is provided and each application usually provides its own rules.

The SELinux context

The operation of SELinux is totally different from traditional Unix rights.

The SELinux security context is defined by the trio identity+role+domain.

The identity of a user depends directly on his Linux account. An identity is assigned one or more roles, but to each role corresponds to one domain, and only one.

It is according to the domain of the security context (and thus the role) that the rights of a user on a resource are evaluated.

SELinux context

The terms "domain" and "type" are similar. Typically "domain" is used when referring to a process, while "type" refers to an object.

The naming convention is: user_u:role_r:type_t.

The security context is assigned to a user at the time of his connection, according to his roles. The security context of a file is defined by the chcon (change context) command, which we will see later in this document.

Consider the following pieces of the SELinux puzzle:

  • The subjects
  • The objects
  • The policies
  • The mode

When a subject (an application for example) tries to access an object (a file for example), the SELinux part of the Linux kernel queries its policy database. Depending on the mode of operation, SELinux authorizes access to the object in case of success, otherwise it records the failure in the file /var/log/messages.

The SELinux context of standard processes

The rights of a process depend on its security context.

By default, the security context of the process is defined by the context of the user (identity + role + domain) who launches it.

A domain being a specific type (in the SELinux sense) linked to a process and inherited (normally) from the user who launched it, its rights are expressed in terms of authorization or refusal on types linked to objects:

A process whose context has security domain D can access objects of type T.

The SELinux context of standard processes

The SELinux context of important processes

Most important programs are assigned a dedicated domain.

Each executable is tagged with a dedicated type (here sshd_exec_t) which automatically switches the associated process to the sshd_t context (instead of user_t).

This mechanism is essential since it restricts the rights of a process as much as possible.

The SELinux context of an important process - example of sshd


The semanage command is used to manage SELinux rules.

semanage [object_type] [options]


$ semanage boolean -l
Options Observations
-a Adds an object
-d Delete an object
-m Modify an object
-l List the objects

The semanage command may not be installed by default under Rocky Linux.

Without knowing the package that provides this command, you should search for its name with the command:

dnf provides */semanage

then install it:

sudo dnf install policycoreutils-python-utils

Administering Boolean objects

Booleans allow the containment of processes.

semanage boolean [options]

To list the available Booleans:

semanage boolean –l
SELinux boolean    State Default  Description
httpd_can_sendmail (off , off)  Allow httpd to send mail


As you can see, there is a default state (eg. at startup) and a running state.

The setsebool command is used to change the state of a boolean object:

setsebool [-PV] boolean on|off


sudo setsebool -P httpd_can_sendmail on
Options Observations
-P Changes the default value at startup (otherwise only until reboot)
-V Deletes an object


Don't forget the -P option to keep the state after the next startup.

Administering Port objects

The semanage command is used to manage objects of type port:

semanage port [options]

Example: allow port 81 for httpd domain processes

sudo semanage port -a -t http_port_t -p tcp 81

Operating modes

SELinux has three operating modes:

  • Enforcing

Default mode for Rocky Linux. Access will be restricted according to the rules in force.

  • Permissive

Rules are polled, access errors are logged, but access will not be blocked.

  • Disabled

Nothing will be restricted, nothing will be logged.

By default, most operating systems are configured with SELinux in Enforcing mode.

The getenforce command returns the current operating mode



$ getenforce

The sestatus command returns information about SELinux



$ 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
Max kernel policy version: 33

The setenforce command changes the current operating mode:

setenforce 0|1

Switch SELinux to permissive mode:

sudo setenforce 0

The /etc/sysconfig/selinux file

The /etc/sysconfig/selinux file allows you to change the operating mode of SELinux.


Disabling SELinux is done at your own risk! It is better to learn how SELinux works than to disable it systematically!

Edit the file /etc/sysconfig/selinux



/etc/sysconfig/selinux is a symlink to /etc/selinux/config

Reboot the system:

sudo reboot


Beware of the SELinux mode change!

In permissive or disabled mode, newly created files will not have any labels.

To reactivate SELinux, you will have to reposition the labels on your entire system.

Labeling the entire system:

sudo touch /.autorelabel
sudo reboot

The Policy Type

SELinux provides two standard types of rules:

  • Targeted: only network daemons are protected (dhcpd, httpd, named, nscd, ntpd, portmap, snmpd, squid and syslogd)
  • Strict: all daemons are protected


The display of security contexts is done with the -Z option. It is associated with many commands:


id -Z   # the user's context
ls -Z   # those of the current files
ps -eZ  # those of the processes
netstat –Z # for network connections
lsof -Z # for open files

The matchpathcon command returns the context of a directory.

matchpathcon directory


sudo matchpathcon /root
 /root  system_u:object_r:admin_home_t:s0

sudo matchpathcon /
 /      system_u:object_r:root_t:s0

The chcon command modifies a security context:

chcon [-vR] [-u USER] [–r ROLE] [-t TYPE] file


sudo chcon -vR -t httpd_sys_content_t /data/websites/
Options Observations
-v Switch into verbose mode
-R Apply recursion
-u,-r,-t Applies to a user, role or type

The restorecon command restores the default security context (the one provided by the rules):

restorecon [-vR] directory


sudo restorecon -vR /home/
Options Observations
-v Switch into verbose mode
-R Apply recursion

To make a context change survive to a restorecon, you have to modify the default file contexts with the semanage fcontext command:

semanage fcontext -a options file


If you are performing a context switch for a folder that is not standard for the system, creating the rule and then applying the context is a good practice as in the example below!


$ sudo semanage fcontext -a -t httpd_sys_content_t "/data/websites(/.*)?"
$ sudo restorecon -vR /data/websites/

audit2why command

The audit2why command indicates the cause of a SELinux rejection:

audit2why [-vw]

Example to get the cause of the last rejection by SELinux:

sudo cat /var/log/audit/audit.log | grep AVC | grep denied | tail -1 | audit2why
Options Observations
-v Switch into verbose mode
-w Translates the cause of a rejection by SELinux and proposes a solution to remedy it (default option)

Going further with SELinux

The audit2allow command creates a module to allow a SELinux action (when no module exists) from a line in an "audit" file:

audit2allow [-mM]


sudo cat /var/log/audit/audit.log | grep AVC | grep denied | tail -1 | audit2allow -M mylocalmodule
Options Observations
-m Just create the module (*.te)
-M Create the module, compile and package it (*.pp)

Example of configuration

After the execution of a command, the system gives you back the command prompt but the expected result is not visible: no error message on the screen.

  • Step 1: Read the log file knowing that the message we are interested in is of type AVC (SELinux), refused (denied) and the most recent one (therefore the last one).
sudo cat /var/log/audit/audit.log | grep AVC | grep denied | tail -1

The message is correctly isolated but is of no help to us.

  • Step 2: Read the isolated message with the audit2why command to get a more explicit message that may contain the solution to our problem (typically a boolean to be set).
sudo cat /var/log/audit/audit.log | grep AVC | grep denied | tail -1 | audit2why

There are two cases: either we can place a context or fill in a boolean, or we must go to step 3 to create our own context.

  • Step 3: Create your own module.
$ sudo cat /var/log/audit/audit.log | grep AVC | grep denied | tail -1 | audit2allow -M mylocalmodule
Generating type enforcement: mylocalmodule.te
Compiling policy: checkmodule -M -m -o mylocalmodule.mod mylocalmodule.te
Building package: semodule_package -o mylocalmodule.pp -m mylocalmodule.mod

$ sudo semodule -i mylocalmodule.pp
Back to top