Linux SELinux

Security-Enhanced Linux (SELinux) is a Linux kernel security module that provides a mechanism for supporting access control security policies,it is a mandatory access controls (MAC) .
It was a project by NSA and Red Hat and now being developed by Red Hat.
A Linux kernel integrating SELinux enforces mandatory access control policies that confine user programs’ and system servers’ access to files and network resources. Limiting privilege to the minimum required to work reduces or eliminates the ability of these programs and daemons to cause harm if faulty or compromised.

SELinux is based on rules and labels for users , files , processes .
Rules decides which user label is allowed to access which file label and by which process label.
For Example: SELinux rule for web browser is running on port 80/443 , that port has SELinux label of http_t ,
and can be used by a process labeled with SELinux type of http_t
and can access files that have SELinux label of http_sys_content_t .

That is a simple example of SELinux rules and labels, let’s use it.

01. Installing SELinux :

It is installed by default for almost RPM based distributions like: Red hat , CentOS , Fedora , SUSE , OpenSUSE , …
But you can add or remove it as you need.

yum -y install selinux-policy* policycoreutils-python
02. Show SELinux lables :

Z is the key option to use with normal commands ,

SELinux assigns a three string context consisting of a username, role, and domain (or type). This system is more flexible than normally required: as a rule, most of the real users share the same SELinux username, and all access control is managed through the third tag, the domain.
To show the SELinux label for files and directories ls -lZ :

[[email protected] ~]# mkdir test
[[email protected] ~]# ls -ld test/
drwxr-xr-x. 2 root root 6 May  5 14:27 test/
[[email protected] ~]# ls -ldZ test/
drwxr-xr-x. root root unconfined_u:object_r:admin_home_t:s0 test/
[[email protected] ~]#

As the directory was created at root home , it inherits the root home SELinux label of admin_home_t .

Show user SELinux using id -Z
users SELinux is not necessary

[[email protected] root]$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Show processes SELinux labels using ps -Z

[[email protected] ~]# ps -Zaux | grep mysql
system_u:system_r:mysqld_safe_t:s0 mysql   1027  0.0  0.1 113256  1572 ?        Ss   13:17   0:00 /bin/sh /usr/bin/mysqld_safe --basedir=/usr

Another example:

[[email protected] ~]# ps -Zaux | grep nfs
system_u:system_r:nfsd_t:s0     root       8727  0.0  0.0  42692   960 ?        Ss   14:38   0:00 /usr/sbin/rpc.mountd

Show ports SELinux labels using netstat -Z

[[email protected] ~]# netstat -4tlZ | grep nfs
tcp        0      0 0.0.0.0:mountd          0.0.0.0:*               LISTEN      8727/rpc.mountd      system_u:system_r:nfsd_t:s0 
03. SELinux modes:

It may be disabled or enabled and has tow modes:

Permissive : Only logs events , but no rule is enforced (just a watcher ) , use it for testing or troubleshooting .

Enforcing : apply rules and enforce actions to follow rules or it will be denied .

To show current mode use getenforce command :

[[email protected] ~]# getenforce 
Enforcing

To set mode to Permissive ( 0 ) or to Enforcing ( 1 ) , use command setenforce mode

[[email protected] ~]# getenforce 
Enforcing
[[email protected] ~]# setenforce permissive
[[email protected] ~]# getenforce 
Permissive
[[email protected] ~]# setenforce enforcing
[[email protected] ~]# getenforce 
Enforcing
[[email protected] ~]# setenforce 0
[[email protected] ~]# getenforce 
Permissive
[[email protected] ~]# setenforce 1
[[email protected] ~]# getenforce 
Enforcing
[[email protected] ~]#

To disable SELinux , set SELINUX=disabled in configuration file : /etc/selinux/config

then , reboot system, then check.

[[email protected] ~]# getenforce 
Disabled

To show SELinux audit logs :

[[email protected] ~]# grep AVC /var/log/audit/audit.log
04. Configure Files and directories Context :

If we want to use a specific directory for a specific service, it must have the appropriate SELinux context label as the service can use it.
For example: to use a directory for http contents , we must relabel it with correct context .

To know the correct context , search internet , or use manual page for the service , or show the default files context.

[[email protected] ~]# ls -lZ /var/www/
drwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html
[[email protected] ~]#

the default label for http contents is httpd_sys_content_t

and for executable scripts : httpd_sys_script_exec_t

To change file context use semanage fcontext :

semanage fcontext -a -t SELinux_TYPE  /path/to/dir

To relabel to the new context use restorecon :

restorecon -Rv /path/to/dir

let’s do a real example:

[[email protected] ~]# mkdir /web
[[email protected] ~]# ls -ldZ /web/
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /web/

[[email protected] ~]# semanage fcontext -a -t httpd_sys_content_t "/web(/.*)?"
[[email protected] ~]# ls -ldZ /web/
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /web/

[[email protected] ~]# restorecon -Rv /web/
restorecon reset /web context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
[[email protected] ~]# ls -ldZ /web/
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 /web/
[[email protected] ~]#
  • “/web(/.*)?”   is a regex syntax to apply label on that folder ( /web ) and its subdirectories .

Now you can get the correct SELinux type and set it using tow simple commands.

For more information about fcontext :

man semanage-fcontext
05. Configure SELinux port context:

By default , default ports for every service has the correct SELinux type, what if you want the service to use a different port that is not assigned to another service use semanage port :

semanage port -a -t TYPE -p PROTOCOL Port-NUMBER

For example, to allow ssh service to listen on port 2022

semanage port -a -t ssh_port_t -p tcp 2022

To check the current port label use semanage port -l :

[[email protected] ~]# semanage port -l | grep 2022
ssh_port_t                     tcp      2022, 22
[[email protected] ~]#

Good, what if we want to relabel a port that was assigned to a different service previously : replace -a option with -m

For example, to reassign port 2022 to http service :

[[email protected] ~]# semanage port -m -t http_port_t -p tcp 2022
[[email protected] ~]# semanage port -l | grep 2022
http_port_t                    tcp      2022, 80, 81, 443, 488, 8008, 8009, 8443, 9000
[[email protected] ~]#

To check current allowed ports to be used with a service use semanage port -l | grep service
For example , list port labels that start with ftp (^ftp) :

[[email protected] ~]# semanage port -l | grep ^ftp
ftp_data_port_t                tcp      20
ftp_port_t                     tcp      21, 989, 990
ftp_port_t                     udp      989, 990
[[email protected] ~]#

Now you can show and set and change port labels.

06. SELinux Booleans :

Booleans allow parts of SELinux policy to be changed at runtime, without any knowledge of SELinux policy writing. This allows changes, such as allowing services access to NFS volumes, without reloading or recompiling SELinux policy.

It is like an extended functionality with on/off value .

To list all the booleans use semanage boolean -l

[[email protected] ~]# semanage boolean -l | grep http
httpd_can_network_relay        (off  ,  off)  Allow httpd to act as a relay
httpd_can_connect_mythtv       (off  ,  off)  Allow http daemon to connect to mythtv
httpd_can_network_connect_db   (off  ,  off)  Allow HTTPD scripts and modules to connect to databases over the network.

the list start with the boolean name , ( current state  ,  permanent state ) and a description.

OR use getsebool -a

[[email protected] ~]# getsebool -a | grep httpd
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off

To set a boolean value to on/off use command setsebool BOOLEAN-NAME on/off
and get its current state using getsebool BOOLEAN-NAME

For example to enable httpd service to connect to a database over network :

[[email protected] ~]# setsebool httpd_can_network_connect_db on
[[email protected] ~]# getsebool httpd_can_network_connect_db 
httpd_can_network_connect_db --> on
[[email protected] ~]#

Now it is set to on , but it is not permanent, to make sure :

[[email protected] ~]# semanage boolean -l | grep httpd_can_network_connect_db
httpd_can_network_connect_db   (on   ,  off)  Allow HTTPD scripts and modules to connect to databases over the network.
[[email protected] ~]#

It may be good for testing , To set it permanently add -P option :

[[email protected] ~]# setsebool -P httpd_can_network_connect_db on
[[email protected] ~]# semanage boolean -l | grep httpd_can_network_connect_db
httpd_can_network_connect_db   (on   ,   on)  Allow HTTPD scripts and modules to connect to databases over the network.
[[email protected] ~]#
07. Users context :

It is always about ports and files and processes not about users, but for knowledge let’s see it.

To list all user roles context :

semanage user -l

To assign user role to  user (get roles using the above command , for example: user_u ) :

semanage login -a -s user_u USER-NAME

I know it was a long tutorial , but SELinux deserve more, once you understand it , it is easy to remember the commands, use manual pages for more information.

That is it , i hope it was simple , thanks for joining me.
Enjoy !.

Comments are closed.