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 :

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

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

[akm@server02 root]$ id -Z
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

Show processes SELinux labels using ps -Z

[root@server02 ~]# 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:

[root@server02 ~]# 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

[root@server02 ~]# 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 :

[root@server02 ~]# getenforce 
Enforcing

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

[root@server02 ~]# getenforce 
Enforcing
[root@server02 ~]# setenforce permissive
[root@server02 ~]# getenforce 
Permissive
[root@server02 ~]# setenforce enforcing
[root@server02 ~]# getenforce 
Enforcing
[root@server02 ~]# setenforce 0
[root@server02 ~]# getenforce 
Permissive
[root@server02 ~]# setenforce 1
[root@server02 ~]# getenforce 
Enforcing
[root@server02 ~]#

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

then , reboot system, then check.

[root@server02 ~]# getenforce 
Disabled

To show SELinux audit logs :

[root@server02 ~]# 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.

[root@server02 ~]# 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
[root@server02 ~]#

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:

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

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

[root@server02 ~]# restorecon -Rv /web/
restorecon reset /web context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
[root@server02 ~]# ls -ldZ /web/
drwxr-xr-x. root root unconfined_u:object_r:httpd_sys_content_t:s0 /web/
[root@server02 ~]#
  • “/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 :

[root@server02 ~]# semanage port -l | grep 2022
ssh_port_t                     tcp      2022, 22
[root@server02 ~]#

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 :

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

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) :

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

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

[root@server02 ~]# 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

[root@server02 ~]# 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 :

[root@server02 ~]# setsebool httpd_can_network_connect_db on
[root@server02 ~]# getsebool httpd_can_network_connect_db 
httpd_can_network_connect_db --> on
[root@server02 ~]#

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

[root@server02 ~]# 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.
[root@server02 ~]#

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

[root@server02 ~]# setsebool -P httpd_can_network_connect_db on
[root@server02 ~]# 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.
[root@server02 ~]#
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.