Summary: How to configure SELinux on Red Hat.
Date: Around 2014
Refactor: 29 March 2025: Checked links and formatting.
Security Enhanced Linux is an additional method to protect your system, besides updating and a firewall. It is a set of security rules that determine which process can access which files, directories, ports etc. Every file, process, directory and port has a special label called a SELinux context. There a several contexts, but the most interesting one is the type context, which always ends with “_t”.
This article shows some information and commands to work with SELinux. When you encounter a issue on a SELinux enabled system, you should always ask yourself the question, “Could this be caused by SELinux”. So dealing with that question will be the first part.
After that more information will be given about SELinux modes, configfiles and commands.
First determine the mode SELinux is running in. Simply, as root, issue this command: “getenforce”:
[root@localhost ~]# getenforce Enforcing
There are three modes:
To troubleshoot an issue you can temporarily change SELinux to permissive using the command “setenforce”:
[root@localhost ~]# setenforce permissive [root@localhost ~]# getenforce Permissive
Now you can check if you're issue is solved. If it is, the SELinux was the cause.
The easiest way to troubleshoot SELinux issues is by installing “setroubleshoot-server”:
yum install setroubleshoot-server
Now restart the auditd service for picking up the new package:
[root@localhost log]# service auditd restart Stopping auditd: [ OK ] Starting auditd: [ OK ]
Then check for more information and how you could fix it, follow this procedure:
This is an example of the messages and commands when adding a file to a webserver which has a diiferent SELinux context:
[root@localhost ~]# service httpd stop Stopping httpd: [ OK ] [root@localhost ~]# touch /root/file3 [root@localhost ~]# mv /root/file3 /var/www/html/ [root@localhost ~]# service httpd start [root@localhost ~]# curl localhost/file3 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN"> <html><head> <title>403 Forbidden</title> </head><body> <h1>Forbidden</h1> <p>You don't have permission to access /file3 on this server.</p> <hr> <address>Apache/2.2.15 (Red Hat) Server at localhost Port 80</address> </body></html> [root@localhost ~]# tail /var/log/audit/audit.log type=AVC msg=audit(1396895949.472:1430): avc: denied { getattr } for pid=16956 comm="httpd" path="/var/www/html/file3" dev=sda2 ino=917490 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:admin_home_t:s0 tclass=file [root@localhost log]# tail /var/log/messages Apr 7 11:39:13 localhost setroubleshoot: SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/file3. For complete SELinux messages. run sealert -l 352f96a6-1102-4afe-8a2e-1ec0aac4ebb0 [root@localhost log]# sealert -l 352f96a6-1102-4afe-8a2e-1ec0aac4ebb0 SELinux is preventing /usr/sbin/httpd from getattr access on the file /var/www/html/file3. ***** Plugin restorecon (99.5 confidence) suggests ************************* If you want to fix the label. /var/www/html/file3 default label should be httpd_sys_content_t. Then you can run restorecon. Do # /sbin/restorecon -v /var/www/html/file3
Note: In the example the command for fixing one file is shown, if you need to reset more files you can recursively reset them all at once: restorecon -R /var/www/
As mentioned above you can change to a different mode with the setenforce command. You can't use that command to disable SELinux though. To completely disable SELinux edit the config file /etc/sysconfig/selinx
:
[root@localhost log]# cat /etc/sysconfig/selinux # 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=enforcing # SELINUXTYPE= can take one of these two values: # targeted - Targeted processes are protected, # mls - Multi Level Security protection. SELINUXTYPE=targeted
After editing the file, reboot the machine. Note that after disabling SELinux, the only way to enable it again is to edit this file again and reboot again. This will cause the system to start relabeling everything! Especially on larger systems this might take a long time, so think before you do this. The system will not be available during relabeling!
Note: If you'd make a typo in the configfile SELinux will fall back to “permissive”.
SELinux is used for processes, ports, files etc. As explained before, the context is quite important, and normally defined by the parent directory. As shown above, if a file is created and inherits the context of it's parent, it keeps that context when it's moved (mv) or copied with the -a option (-a).
Most commands have an option to display the SELinux context (usually -Z):
[root@localhost log]# ps -ZC httpd LABEL PID TTY TIME CMD unconfined_u:system_r:httpd_t:s0 16948 ? 00:00:00 httpd unconfined_u:system_r:httpd_t:s0 16951 ? 00:00:00 httpd [root@localhost log]# ls -Z /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 error drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 icons [root@localhost log]# netstat -Z Active Internet connections (w/o servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name Security Context tcp 0 64 192.168.25.128:ssh 192.168.25.1:63900 ESTABLISHED 16303/sshd system_u:system_r:sshd_t:s0-s0:c0.c1023
There are a few commands you can use to change the context:
semanage fcontext -l semanage fcontext -a restorecon
In the example above I've shown how to restore the context for a file inside a directory. But what if you would like to create a second directory which the web server also has to be able to read? SELinux would prevent that since your created directory would not be listed with the context “httpd_sys_content_t”.
First, let's check which directories are listed with that context:
[root@localhost ~]# semanage fcontext -l | grep httpd_sys_content_t /etc/htdig(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /srv/([^/]*/)?www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /srv/gallery2(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/drupal.* all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/htdig(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/icecast(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/mythtv/data(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/mythweb(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/ntop/html(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/openca/htdocs(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/selinux-policy[^/]*/html(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/lib/cacti/rra(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/lib/graphite-web(/.*) all files system_u:object_r:httpd_sys_content_t:s0 /var/lib/htdig(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/lib/trac(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/www/icons(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/www/svn/conf(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
Since all these directories have the “httpd_sys_content_t” the web server will be allowed to access the files inside of them. Note the (/.*)?
section at the end of each line, it's a regular expression which means “optionally, match a / followed by any number of characters” which will match the directory before it and everything in that directory recursively.
Now, we want to add the /virtual directory in which our index.html is created. This has a different SELinux context:
[root@localhost ~]# mkdir /virtual [root@localhost ~]# touch /virtual/index.html [root@localhost ~]# ls -Zd /virtual/ drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /virtual/ [root@localhost ~]# ls -Z /virtual/ -rw-r--r--. root root unconfined_u:object_r:default_t:s0 index.html
Now we set the SELinux context of “httpd_sys_content_t” to the /virtual directory in the SELinux ruleset:
[root@localhost ~]# semanage fcontext -a -t httpd_sys_content_t '/virtual(/.*)?' [root@localhost ~]# semanage fcontext -l | grep httpd_sys_content_t /etc/htdig(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /srv/([^/]*/)?www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /srv/gallery2(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/drupal.* all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/htdig(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/icecast(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/mythtv/data(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/mythweb(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/ntop/html(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/openca/htdocs(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /usr/share/selinux-policy[^/]*/html(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/lib/cacti/rra(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/lib/graphite-web(/.*) all files system_u:object_r:httpd_sys_content_t:s0 /var/lib/htdig(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/lib/trac(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/www/icons(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /var/www/svn/conf(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 /virtual(/.*)? all files system_u:object_r:httpd_sys_content_t:s0 [root@localhost ~]# ls -Zd /virtual/ drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /virtual/
As you can see, the /virtual now has the correct context in the SELinux ruleset, but not yet on the directory. We need restorecon to do that:
[root@localhost ~]# restorecon -RFvv /virtual/ restorecon reset /virtual context unconfined_u:object_r:default_t:s0->system_u:object_r:httpd_sys_content_t:s0 restorecon reset /virtual/index.html context unconfined_u:object_r:default_t:s0->system_u:object_r:httpd_sys_content_t:s0 [root@localhost ~]# ls -Zd /virtual/ drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /virtual/ [root@localhost ~]# ls -Z /virtual/ -rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.html
As you can see, everything is correct now, and since SELinux works directly at the kernel nothing has to be restarted.
If you added a directory with a specific context and you need to remove it again you can do it like this:
semanage fcontext -d '/virtual(/.*)?'
SELinux are switches that change the behavior of the SELinux policy. They can be disabled or enabled. To manage the SELinux booleand you'll use the following commands:
getsebool <boolean> getsebool -a setsebool setsebool -P semanage boolean -l
Note that packages with SELinux booleans can be found by looking for a manpage like this:man -k '_selinux'
So another example to show you what this might mean. Say you want your webserver also to manage some files in home directories. Even if you would add your home directory on the way described above this will not work since there is a boolean preventing this.
First, let's take a look at the httpd related booleans:
[root@localhost ~]# getsebool -a | grep httpd allow_httpd_anon_write --> off allow_httpd_mod_auth_ntlm_winbind --> off allow_httpd_mod_auth_pam --> off allow_httpd_sys_script_anon_write --> off httpd_builtin_scripting --> on httpd_can_check_spam --> 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 httpd_dbus_avahi --> on httpd_enable_cgi --> on httpd_enable_ftp_server --> off httpd_enable_homedirs --> off httpd_execmem --> off httpd_manage_ipa --> off httpd_read_user_content --> off httpd_run_stickshift --> off httpd_serve_cobbler_files --> off httpd_setrlimit --> off httpd_ssi_exec --> off httpd_tmp_exec --> off httpd_tty_comm --> on httpd_unified --> on httpd_use_cifs --> off httpd_use_fusefs --> off httpd_use_gpg --> off httpd_use_nfs --> off httpd_use_openstack --> off httpd_verify_dns --> off
As you can see, there are quite a few and the one we need is disabled. So now, let's enable it:
[root@localhost ~]# setsebool httpd_enable_homedirs on [root@localhost ~]# getsebool -a | grep http.*homedir httpd_enable_homedirs --> on
But now, if we look at persistency we see that at the next reboot this will be reset:
[root@localhost ~]# semanage boolean -l | grep http.*homedir httpd_enable_homedirs (on , off) Allow httpd to read home directories
Now, let's make it persistent:
[root@localhost ~]# setsebool -P httpd_enable_homedirs on [root@localhost ~]# semanage boolean -l | grep http.*homedir httpd_enable_homedirs (on , on) Allow httpd to read home directories
SELinux is also configured for using default options. I ran into a problem when an application user in a non-default home directory. We use X-redirection but that stopped working because of SELinux. When trying to add the xauth magic cookie we ran into this error:
xauth: timeout in locking authority file /application/acceptance/appuser/.Xauthority
To solve this error a few steps are required. First of all check if the file already exists. This has to be the case, as I've seen the fix below fail when this was not the case. If not, as the application user create the file with this command:
[appuser@selinuxbox ~]$ touch .Xauthority
Then you need to configure SELinux to include home directory checking through the passwd file. To do so, open the semanage config file and set the usepasswd option to true:
[adminsjoerd@selinuxbox ~]$ sudo vi /etc/selinux/semanage.conf [adminsjoerd@selinuxbox ~]$ cat /etc/selinux/semanage.conf | grep usepasswd # usepasswd check tells semanage to scan all pass word records for home directories #usepasswd=False usepasswd=True
Then configure the home directory root to be considered as a home directory:
[adminsjoerd@selinuxbox ~]$ sudo semanage fcontext -a -e /home /application/acceptance
Note: in the above command, please do not add an ”/“ at the end, this will break it.
Then, because the home dir already exists, relabel it like this:
[adminsjoerd@selinuxbox ~]$ sudo restorecon -R /application
Which sets these settings in the fcontext and home dirs:
[adminsjoerd@selinuxbox ~]$ sudo semanage fcontext -l | grep appl ... /application/acceptance = /home [adminsjoerd@selinuxbox ~]$ ls -lZd /application/acceptance drwxr-xr-x. appuser appuser system_u:object_r:home_root_t:s0 /application/acceptance
There is also a graphical tool available, system-config-selinx, but it's not installed by default. You can install and use it like this:
yum install policycoreutils-gui system-config-selinx
This is especially useful if you need to do some policy editing, like adding an allowed port for a web server: