Magazine

Switching SELinux on and off

Posted on the 29 May 2021 by Satish Kumar @satish_kumar86

This isperhaps a weird section to begin with, but disabling SELinux is a commonly requested activity. Some vendors do not support their application running on a platform that has SELinux enabled, as those vendors do not have the expertise to develop SELinux policies for their own applications, or are not able to educate their own support lines to deal with SELinux.

Furthermore, system administrators are generally reluctant to use security controls they do not understand or find too complex to maintain. Luckily, SELinux is becoming a de facto standard technology in several Linux distributions, which is increasing its exposure and understanding among administrators. SELinux is also capable of selectively disabling its access controls for a part of a system rather than requiring us to disable it for a complete system.

Setting the global SELinux state

SELinux supports three major states that it can be in: disabledpermissive, and enforcing. These states are set in the /etc/selinux/config file, through the SELINUX variable, as illustrated in the following code snippet:

$ grep ^SELINUX= /etc/selinux/config
SELINUX=enforcing

When the init system process loads the SELinux policy, the SELinux code checks the state that the administrator has configured. The states are described as follows:

  • If the state isdisabled, then the SELinux code disables further support, booting the system further without activating SELinux.
  • If the state ispermissive, then SELinux is active but will not enforce its policy on the system. Instead, SELinux will report any violation against the policy, but will not prevent the action itself. Thisis sometimes calledhost intrusion detectionas it works in reporting-only mode.
  • If the state isenforcing, then SELinux is active and will enforce its policy on the system. Violationsare reported and denied. This is sometimes calledhost intrusion prevention, as it enforces the rules while logging the actions it takes.

We can use the getenforce command or the sestatus command to get information about the current state of SELinux, like so:

$ sestatus | grep mode
Current mode:	enforcing
$ getenforce
Enforcing

It is also possible to query the/sys/fs/selinux/enforcepseudo-file to get similar information. If the file returns1, then SELinux is in enforcing mode. If it returns0, then it is in permissive mode. The following code snippet shows SELinux in enforcing mode:

$ cat /sys/fs/selinux/enforce
1

When we change the /etc/selinux/config file, then we need to reboot the system for the changes to take effect. However, if we boot a system without SELinux support (disabled), re-enabling SELinux support alone will not suffice: the administrator will need to make sure that all files on the system are relabeled (the context of all files needs to be set). Without SELinux support, Linux will create and update files without updating or setting the SELinux labels on those files. When the system is later rebooted with SELinux support, SELinux will not have any knowledge of the context of a file unless the labels are reset.

In many situations, administrators often want to disable SELinux when it starts preventing certain tasks. This is careless to say the least, and here’s why:

  • SELinux is a security component—part of the operating system. Disabling SELinux is like disabling a firewall because it is blocking some communication. It might help because it’s a faster way of getting something to work again, but you’re removing measures that were enabled to protect you.
  • Just as with a firewall, SELinux is configurable by rules. If an application is prevented from working correctly, we need to update the rules for that application, just as with additional firewall rules that enable a particular network flow. 
  • In the worst case, when we want to allow every action an application performs unconditionally, we can still leave SELinux on and just run this application in an unrestricted SELinux domain, called apermissivedomain.

Distributions put significant effort in the integration of SELinux within their products, and they have awesome support channels to help you out if all things fail.

Switching to permissive or enforcing mode

Most distribution-provided Linux kernels allow switching between enforcing and permissivemode through a simple administrativecommand. This feature is called theSELinux development modeand is supported by theCONFIG_SECURITY_SELINUX_DEVELOPkernel configuration parameter. This kernel parameter, if set, also has the Linux kernel boot in permissive mode first, unless a specific boot option (enforcing=1) is set.

Although we could consider this development mode a risk (all a malicious person would need to do is switch SELinux to permissive mode to disable its access controls), switching the mode requires strong administrative privileges (like therootuser has), which most application domains don’t have.

The command to switch between permissive mode and enforcing mode is thesetenforcecommand. It takes a single argument:0(permissive) or1(enforcing). Thepermissiveandenforcingstrings are allowed by the command as well.

The change takes effect immediately. For instance, we can use the following command to switch to permissive mode:

# setenforce 0

The effect of setenforce is the same as writing the right integer value into the /sys/fs/selinux/enforce pseudo-file, as illustrated in the following code snippet:

# echo 0 > /sys/fs/selinux/enforce

Switching between permissive and enforcing mode can be of interest for policy developers or system administrators who are modifying the system to use SELinux properly. We can also use it to quickly verify whether an application warning or error is due to SELinux access controls or not—assuming the application is not SELinux-aware, which we will talk about in theUnderstanding SELinux-aware applicationssection.

On production systems, it might be of interest to disable the ability to switch to permissive mode. Disabling this feature usually requires the Linux kernel to be rebuilt, but SELinux policy developers have also thought of a different way to disallow users from toggling the SELinux state. The privileges that users need to switch to permissive mode are conditional, and system administrators can easily toggle this to disable switching back from enforcing mode to permissive mode. The condition is implemented through an SELinux Boolean calledsecure_mode_policyloadwhose default value isoff(meaning switching SELinux state is allowed).

SELinux Booleansareconfigurable options that take on a single value (onoroff, althoughtrue/falseand1/0are valid values as well) and manipulate parts of the active SELinux policy. The value of the conditionals can be persisted (meaning they survive reboots) or be kept only during the current boot session. We can persist the value across reboots by adding-Pto thesetseboolcommand, as follows:

# setsebool -P secure_mode_policyload on

The use of thesecure_mode_policyloadSELinux Boolean allows administrators to restrict switching from enforcing mode back to permissive mode. This does not disable SELinux completely, but only toggles whether it will act upon its policies or not.

Switchingfrom a disabled state to a running state is not supported. However, the reverse is possible, but only under the following condition: if the Linux kernel is built with theSECURITY_SELINUX_DISABLEkernel configuration parameter, then services such asinitcan effectively disable SELinux at runtime, but only if no SELinux policy is loaded yet. This functionality, however, is not recommended to be actively used, and was only introduced for platforms where boot options are hard to use. The feature is marked as deprecated in recent kernels as such platforms are few in number.

Using kernel boot parameters

Using thesetenforcecommand makes sense when we want to switch to permissive or enforcingmode at a point in time when we have interactive access to the system. But what if we need this on system boot? If the system refuses to boot properly due to SELinux access controls, we cannot edit the/etc/selinux/configfile. Luckily, we can change the SELinux state through other means as well.

The solution is to use kernel boot parameters. We can boot a Linux system with one or two parameters that take precedence over the/etc/selinux/configsetting, as follows:

  • selinux=0: This informs the system to disable SELinux completely, and has the same effect as settingSELINUX=disabledin the configuration file. When set, the other parameter (enforcing) is not consulted. Please remember that booting a system with SELinux disabled means that to enable it again, we need to relabel all files and resources on the filesystem. Theselinux=parameter is supported through theCONFIG_SECURITY_SELINUX_BOOTPARAMkernel configuration.
  • enforcing=0: This informs the system to run SELinux in permissive mode, and has the same effect as settingSELINUX=permissivein the configuration file.
  • enforcing=1: This informs the system to run SELinux in enforcing mode, and has the same effect as settingSELINUX=enforcingin the configuration file.

Consider a Linux system that uses GRUB2 as its boot loader, and we want to add enforcing=0 to the boot entry. To accomplish this, we execute the following steps:

  • Reboot the system until the GRUB2 boot screen comes up.
  • Navigate with the arrow keys to the boot entry for which the SELinux state must be altered. This is usually the default boot entry and should be already selected.
  • Press theEkey to edit the boot entry line. Do this before the GRUB2 timer reaches zero; otherwise, the system will continue to boot.
  • Use the arrow keys to go to the end of the line that starts withoptions. If no such line exists, go to the end of the line that starts withlinux,linux16, orlinuxefi.
  • Addenforcing=0to the end of this line.
  • PressCtrl+XorF10to boot the entry.

Other bootloaders have similar approaches to changing the boot line without persisting it for every reboot. Consult your distribution documentation for more details.

Alongside the SELinux-specific parameters, there are a fewLinux Security Module(LSM)-relatedboot parameters that can be useful to know, especially when you are combining multiple LSM modules on the same system. These are detailed as follows:

  • Thelsm.debugboot parameter enables LSM initialization debugging output, showing which LSM modules it effectively enables or ignores, and which LSM modules are considered as exclusive.
  • Thelsm=lsm1,…,lsmNoption chooses the order of LSM initialization. For instance, to initialize SELinux before lockdown, uselsm=selinux,lockdown.
  • Thesecurity=boot parameter enables selection of the active, major/exclusive LSM module. This parameter, however, is deprecated, favoring thelsm=parameter.

When using SELinux in production, it might be wise to properly protect the boot menu—for instance, by password-protecting the menu and regularly verifying the integrity of the boot menu files.

Disabling SELinux protections for a single service

Since policy version 23 (which came with Linux 2.6.26), SELinux also supports a more granularapproach to switching between permissive and enforcing mode: the use of permissive domains. As mentioned before, a domain is a term that SELinux uses for types (labels) assigned to processes. Withpermissive domains, we canmark one or more domains as permissive (and, as such, not enforced by SELinux rules), even though the rest of the system is still running in enforcing mode.

To make a domain permissive, we use thesemanagecommand, as follows:

# semanage permissive -a minidlna_t

With the same semanage command, we can list the currently defined permissive domains, like this:

# semanage permissive -l
Builtin Permissive Types
Customized Permissive Types
minidlna_t

In the previous example, you will notice that there is also room forbuilt-inpermissive types. These are domains that have been marked as permissive by the policy developers of theLinux distribution itself. Some distributions opt to introduce new application policies in permissive mode first, allowing users to test out the policies before enforcing them. When that is the case, you can find these permissive domains underBuiltin Permissive Types.

Another method for listing the custom permissive types (those not marked as permissive through the distribution) is to use thesemodulecommand. In the previous chapter, we briefly touched on this command when talking about SELinux policy modules. We can use it to list the SELinux policy modules that havepermissive_in their name because thesemanage permissivecommand generates a small SELinux policy module to mark the domain as permissive, as illustrated in the following code snippet:

# semodule -l | grep permissive_
permissive_minidlna_t

To remove the permissive mode from the domain, pass the -d argument to the semanage command. This is only possible for domains that the system administrator marked as permissive, though—distribution-provided permissive domains cannot be switched to enforcing mode through this approach. This is illustrated in the following code snippet:

# semanage permissive -d minidlna_t

When a domain is marked as permissive, the application should behave as if SELinux is not enabled on the system (SELinux will not be enforcing anything that particular application/domain does), making it easier for us to discover whether SELinux is really causing a permission issue. Note, though, that other domains (including those that interact with a permissive domain) are themselves still governed and enforced through the SELinux access controls.

Understanding SELinux-aware applications

Most applicationsthemselves do not have knowledge that they are running on an SELinux-enabled system. Without this knowledge, permissive mode truly means that the application behaves as if SELinux were not enabled to begin with. However, some applications actively rely on the SELinux policy to make access control decisions, or interact with SELinux for further information gathering. We call these applicationsSELinux-awarebecause they change their behavior based on the SELinux-related information available.

Sadly, many of these SELinux-aware applications do not properly validate whether they are running in permissive mode or not. As a result, running these applications in a permissive domain (or the entire system in permissive mode) will generally not result in the application running as if SELinux were not active.

Examples ofsuch applications are theSecure Shell(SSH) daemon, the system login service, theinitsystem, and some cron daemons, as well as several core Linux utilities (such aslsandid). They might show permission failures or different behavior based on the SELinux policy, even if SELinux is not in enforcing mode.

We can find out whether an application is SELinux-aware by checking whether the application is dynamically linked with thelibselinuxlibrary. Such checks are possible withreadelf,ldd, orobjdump, as follows:

$ readelf -d /bin/ls | grep selinux
0x0000000000000001 (NEEDED)		Shared library: [libselinux.so.1]
$ ldd /bin/ls | grep selinux
libselinux.so.1 => /lib64/libselinux.so.1 (0x00005d415f3f03f0)
$ objdump -x /bin/ls | grep selinux
NEEDED	libselinux.so.1

Knowing whether an application is SELinux-aware or not can help in troubleshooting failures, as the application’s behavior might still be different between a disabled SELinux state and a permissive SELinux state.

Up until now, we’ve focused on enabling or disabling SELinux, and thus on a granular or coarse-grained matter. Once it is enabled though, its interaction with the administrator will be throughpolicy enforcement and logging. So, let’s look at how SELinux handles logging.


Back to Featured Articles on Logo Paperblog