Linux distributions come with Discretionary Access Control (DAC) preinstalled in them. A sudo user is usually created in a Linux system to work at root-level privileges. DAC system provides the sudo user with all the administrator rights which may be a security threat if the sudo user is not trustworthy.

 

SELinux is a Mandatory Access Control (MAC) system that replaced traditional DAC systems in modern Linux OS. SELinux allows the system admins to have more control over who can access the system. SELInux defaults to deny anything that is not explicitly allowed. Red Hat Enterprise Linux and all of its derivatives e.g. CentOS, Fedora, etc have SELinux already configured and running on the new installation.

 

SELinux has two modes of operation

 

SELinux Permissive Mode: While running in permissive mode, it works like a traditional DAC system but logs any violation to SELinux.

 

SELinux Enforcing Mode: The enforcing mode denies by default access to everything even for a sudo user until and unless it is explicitly allowed by writing a rule.

 

SELinux makes use of a set of rules, also known as Security Policies, to define what services, processes, and applications are accessible to which user on the system. Each time an application or a process makes a request to access a file in the operating system, SELinux checks its AVC to identify the permissions that the program is allowed to use the file with.  In case that permission is being denied, an "avc:denied" is logged in /var/log messages.

 

As a SysAdmin, you must be aware of the following commands to work with SELinux:

  1. Verifying SELinux installation.
  2. Enable and Disable SELinux.
  3. The different SELinux modes.
  4. What is SELinux context.
  5. SELinux boolean.
  6. Getting SELinux to work with modified applications.
  7. Creating SELinux policy for a custom application.
  8. Linux hardening automation.

 

How to verify if SELinux is installed or not

First, use the following command:

sudo rpm -aq | grep selinux

 

The following output must be shown on a CentOS 7 system.

libselinux-2.5-14.1.el7.x86_64
 selinux-policy-3.13.1-252.el7_7.6.noarch
 selinux-policy-targeted-3.13.1-252.el7_7.6.noarch
 libselinux-utils-2.5-14.1.el7.x86_64
 libselinux-python-2.5-14.1.el7.x86_64

 

The following packages must be installed in the system to work with SELinux:

sudo yum install policycoreutils policycoreutils-python setools setools-console setroubleshoot

 

Disable SELinux Security Configuration

Many systems come preinstalled with SELinux but need to enable it manually.

To check SELinux status use the following command:

sudo sestatus

 

If SELinux is disabled, then it can be enabled by editing line number 5 in the following file:

sudo nano /etc/selinux/config

12

3

4

5

6

7

8

9

10

11

12

# This file controls the state of SELinux on the system.

# SELINUX= can take one of these three values:

#     enforcing - SELinux security policy is enforced.

#     permissive - SELinux prints warnings instead of enforcing.

#     disabled - No SELinux policy is loaded.

SELINUX=disabled

# SELINUXTYPE= can take one of three values:

#     targeted - Targeted processes are protected,

#     minimum - Modification of targeted policy. Only selected processes are protected.

#     mls - Multi Level Security protection.

SELINUXTYPE=targeted

 

 

  • The system needs to be rebooted after editing this file.

 

SELinux Modes:

SELinux has two modes – Permissive and Enforcing.

  • SELinux policy modules can be listed by issuing the command sudo semodule -l
  • To check which is mode SELinux is running use: sudo getenforce

SELinux Permissive mode:

The permissive mode does not make use of any SELinux policies and allows everything, the same as a DAC system. However, it logs the denied actions in the /var/log/audit/audit.log file.

 

The Permissive mode is usually used when a user wants to configure the system as it allows us to make changes to the System as a sudo user.

 

To change the mode to permissive the command should be sudo setenforce 0

 

What is SELinux Context:

SELinux has a context for every file, user, and process. SELinux context is divided into 3 parts: user, role, and type. A SELinux policy defines which user gets which roles. Each role will define what type of files each user can access.

 

SELinux Boolean:

Any Policy can be modified without reloading or recompiling it using SELinux Boolean variables. A list of Boolean variables can be seen by entering "getsebool -a". For example, to see the Booleans for apache webserver a command can be run as:  sudo getsebool -a | grep "httpd_can"

 

The output resembles the following:

httpd_can_check_spam --> off

httpd_can_connect_ftp --> off

httpd_can_connect_ldap --> off

httpd_can_connect_mythtv --> off

httpd_can_connect_zabbix --> off

httpd_can_network_connect --> off

httpd_can_network_connect_cobbler --> off

httpd_can_network_connect_db --> off

httpd_can_network_memcache --> off

httpd_can_network_relay --> off

httpd_can_sendmail --> off

 

The value of a Boolean can be changed by using sudo setsebool -P httpd_can_network_connect ON. This -P flag persists through reboots.

 

Getting SELinux to work with modified applications

Sometimes you need to run applications such as Apache webserver on a port other than standard port 80, or park the website files outside the default /var/www/ directory. In such cases, SELinux won't let the webserver start as it expects the connection to through standard ports only.

 

The following commands lets you check which ports are allowed for HTTPD (Apache webserver) in SELinux default policy:

sudo semanage port -l | grep http

http_cache_port_t              tcp      8080, 8118, 8123, 10001-10010

http_cache_port_t              udp      3130

http_port_t                    tcp      80, 81, 443, 488, 8008, 8009, 8443, 9000

pegasus_http_port_t            tcp      5988

pegasus_https_port_t           tcp      5989

 

If Apache is running on a non-standard port 2907 and website files are stored in /var/test_www, SELinux policy can be modified using:

sudo semanage port -a -t http_port -p tcp 2907

sudo semanage fcontext -a -e /var/www /var/test_www

sudo restorecon -Rv /var/

 

 

Creating SELinux Policy for a custom application

Let’s assume a simple application named "mydaemon" is created, that can read /var/log/messages file.

 

A systemd unit file can be created as nano mydaemon.service

 

[Unit]

Description=Simple testing daemon

 

[Service]

Type=simple

ExecStart=/usr/local/bin/mydaemon

 

[Install]

WantedBy=multi-user.target

 

 

Install and start the daemon:

cp mydaemon /usr/local/bin

cp mydaemon.service /usr/lib/system/system

systemctl start mydaemon

 

Varify that daemon is not confined by SELinux

ps -efZ | grep mydaemon

system_u:system_r:unconfined_service_t:s0 root 4117    1  0 16:56 ?        00:00:00 /usr/local/bin/mydaemon

sepolicy generate -init /usr/local/bin/daemon

Created the following files:

/home/example.user/mysepol/mydaemon.te # Type Enforcement file

/home/example.user/mysepol/mydaemon.if # Interface file

/home/example.user/mysepol/mydaemon.fc # File Contexts file

/home/example.user/mysepol/mydaemon_selinux.spec # Spec file

/home/example.user/mysepol/mydaemon.sh # Setup Script

 

Rebuild the system policy with the new policy module using the setup script created by the previous command:

./mydaemon.sh

Building and Loading Policy

+ make -f /usr/share/selinux/devel/Makefile mydaemon.pp

Compiling targeted mydaemon module

Creating targeted mydaemon.pp policy package

rm tmp/mydaemon.mod.fc tmp/mydaemon.mod

+ /usr/sbin/semodule -i mydaemon.pp

...

 

restorecon -v /usr/local/bin/mydaemon /usr/lib/systemd/system

 

Restart the daemon, and check that it now runs confined by SELinux:

systemctl restart mydaemon

ps -efZ | grep mydaemon

system_u:system_r:mydaemon_t:s0 root        8150       1  0 17:18 ?        00:00:00 /usr/local/bin/mydaemon

 

Because the daemon is now confined by SELinux, SELinux also prevents it from accessing /var/log/messages. Display the corresponding denial message:

ausearch -m AVC =ts recent

...

type=AVC msg=audit(1590247112.719:5935): avc:  denied  { open } for  pid=8150 comm="mydaemon" path="/var/log/messages" dev="dm-0" ino=2430831 scontext=system_u:system_r:mydaemon_t:s0 tcontext=unconfined_u:object_r:var_log_t:s0 tclass=file permissive=1

...

 

Use the audit2allow tool to suggest changes

Ausearch -m AVC -ts recent | audit2allow -R

require {

               type mydaemon_t;

}

 

#============= mydaemon_t ==============

logging_write_generic_logs(mydaemon_t)

 

Because rules suggested by audit2allow can be incorrect in some cases, use only a part of its output to find the corresponding policy interface:

grep -r "logging_write_generic_logs" /usr/share/selinux/devel/include | grep .if

/usr/share/selinux/devel/include/system/logging.if:interface(logging_write_generic_logs',

 

 

Check the definition of the interface:

cat /usr/ share/selinux/devel/include/system/logging.if

 

...

interface(logging_write_generic_logs',

        gen_require(`

                type var_log_t;

        ')

         files_search_var($1)

        allow $1 var_log_t:dir list_dir_perms;

        write_files_pattern($1, var_log_t, var_log_t)

')...

 

In this case, you can use the suggested interface. Add the corresponding rule to your type enforcement file:

echo "logging_write_generic_logs(mydaemon_t)" >> mydaemon.te

 

Reinstall the policy:

./mydaemon.sh

Building and Loading Policy

+ make -f /usr/share/selinux/devel/Makefile mydaemon.pp

Compiling targeted mydaemon module

Creating targeted mydaemon.pp policy package

rm tmp/mydaemon.mod.fc tmp/mydaemon.mod

+ /usr/sbin/semodule -i mydaemon.pp

...

 

Verification

Check that your application runs confined by SELinux, for example:

ps -efZ | grep mydaemon

system_u:system_r:mydaemon_t:s0 root        8150       1  0 17:18 ?        00:00:00

/usr/local/bin/mydaemon

 

Verify that your custom application does not cause any SELinux denials:

ausearch -m AVC -ts recent

<no matches>

 

Linux Hardening Automation

 

SELinux is a really handy tool for enforcing security policies in high-security server environments. Using tools such as SELinux and enforcing a secured configuration policy is mandatory in every network that handles sensitive information. The common process of hardening requires to:

 

a. Perform impact analysis, indicating what will be the impact of each configuration change on production.

 

b. Implement each policy on the correct machine and environment.

 

c. Monitor the compliance posture, remediate any undesired change and maintain compliance through the dynamic nature of the network.

 

This complex process often leads organizations to neglect hardening, therefore, being exposed to audit failures and fines and cyber attacks. By automating the hardening process organizations don’t need to either hold the knowledge and the manpower in-house since tools such as CalCom Hardening Automation Suite turns hardening into a matter of a click of a button. To learn more about hardening automation, continue your reading here.

 

You might be interested