The default SELinux settings in Fedora work fairly well, but I made a few modifications.
First, I disabled the execstack and execmod capabilities. Any software that requires either should be considered flawed.
setsebool -P selinuxuser_execstack off
setsebool -P selinuxuser_execmod off
I also disabled ptrace and execmem. Ptrace is used to trace processes. It is useful in debugging applications to watch systemcalls. Denying ptrace means that users cannot use the strace command, which I have found indispensable to troubleshoot application issues when the error logs don’t provide valuable information. The deny_execmem prevents an application from marking the memory as both writable and executable.
setsebool -P deny_ptrace on
setsebool -P deny_execmem on
My Apache webserver needs to access an NFS share and the default SELinux prohibits this, so I enabled httpd_use_nfs:
setsebool -P httpd_use_nfs on
I also enabled secure_mode_insmod, which means that new kernel modules cannot be loaded. This caused a problem with my network settings because I use vlan tagging. The secure_mode_insmod interfered with the 8021q module. To mitigate this, I setup a cronjob to execute the following every hour:
/usr/sbin/getsebool secure_mode_insmod 2>&1 |grep ‘on’ >/dev/null 2>&1 || /usr/sbin/setsebool secure_mode_insmod on
I had to build a local policy for exceptions to the targeted SELinux rules. Discovering the needed exceptions is not always easy. The error logs for applications will not tell you when SELinux blocks something. When I troubleshoot an issue, I first check the error output and the logs. The second thing I check is the audit log for AVC entries. You can search for these with ‘ausearch -m avc’, but it won’t give you much information. I prefer to use the audit2allow program to tell me what SELinux blocked and why it blocked it. These are the commands I run when I need to make an exception in SELinux:
cd /etc/selinux/targeted/modules/active/src
cat /var/log/audit/audit.log | audit2allow -m local
vi local.te (make the appropriate changes)
checkmodule -M -m -o local.mod local.te
semodule_package -o local.pp -m local.mod
semodule -i local.pp
Make sure that the checkmodule command is successful before continuing. That will let you know if you are missing something or have a typo.
One important thing to note, don’t setup exceptions when a simple chcon will fix the issue. I’ve run into many situations where the files in question had the incorrect context. For example, my webserver was unable to read a file that I had moved into /var/www/html. The conext of the file was not set to allow Apache to read the file. I could have setup an exception in the local policy, but the correct action was to run ‘chcon unconfined_u:object_r:httpd_sys_content_t:s0‘ on the file.
SELinux does not log all blocks by default. There are some things that are categorized as ‘dontaudit’. It is possible to turn off the ‘dontaudit’ policy, but you will be flooded with logs for syscalls that are not necessarily causing problems. I have only run into one issue that required me to turn off ‘dontaudit’ to fix an application. To disable ‘dontaudit’, run ‘semodule -DB‘. The ‘dontaudit’ policy will re-enable itself when SELinux is reloaded or the system is rebooted. To find the problematic policy after ‘dontaudit’ is disabled, run ‘sesearch –dontaudit -s httpd_t‘ where httpd was the type causing problems.
Here is my local.te file:
module local 1.2; require { class dir { open getattr search write read remove_name add_name }; class file { create open read write execute execute_no_trans getattr }; class chr_file { create open read write execute execute_no_trans getattr }; class process { execmem siginh noatsecure rlimitinh }; class udp_socket listen; class unix_stream_socket { read write }; type admin_home_t; type audisp_t; type auditd_t; type auditd_etc_t; type auditd_log_t; type awstats_t; type chkpwd_t; type httpd_t; type init_t; type insmod_t; type iptables_t; type load_policy_t; type logrotate_t; type mount_t; type mysqld_safe_t; type nfs_t; type postfix_cleanup_t; type postfix_local_t; type postfix_master_t; type postfix_pickup_t; type postfix_qmgr_t; type postfix_showq_t; type postfix_smtpd_t; type postfix_smtp_t; type proc_t; type rpcbind_t; type rpcd_t; type rpm_var_lib_t; type setroubleshootd_t; type sshd_t; type system_dbusd_t; type unconfined_t; type urandom_device_t; type usr_t; type var_lib_t; type var_log_t; type var_t; type user_tmp_t; } #============= auditd_t ============== allow auditd_t audisp_t:process { siginh noatsecure }; #============= awstats_t ============== allow awstats_t admin_home_t:dir { getattr search }; allow awstats_t proc_t:file read; allow awstats_t var_lib_t:dir search; #============= httpd_t ============== allow httpd_t nfs_t:file { execute execute_no_trans }; allow httpd_t usr_t:file write; #============= iptables_t ============== allow iptables_t insmod_t:process { siginh rlimitinh noatsecure }; #============= load_policy_t ============== allow load_policy_t init_t:unix_stream_socket { read write }; #============= logrotate_t ============== allow logrotate_t var_t:dir { add_name read write remove_name }; allow logrotate_t var_t:file getattr; #============= mount_t ============== allow mount_t rpcd_t:process { siginh rlimitinh noatsecure }; #============= mysqld_safe_t ============== allow mysqld_safe_t var_log_t:file open; #============= postfix_master_t ============== allow postfix_master_t postfix_cleanup_t:process { siginh rlimitinh noatsecure }; allow postfix_master_t postfix_local_t:process { siginh rlimitinh noatsecure }; allow postfix_master_t postfix_pickup_t:process { siginh rlimitinh noatsecure }; allow postfix_master_t postfix_qmgr_t:process { siginh rlimitinh noatsecure }; allow postfix_master_t postfix_showq_t:process { siginh rlimitinh noatsecure }; allow postfix_master_t postfix_smtp_t:process { siginh rlimitinh noatsecure }; allow postfix_master_t postfix_smtpd_t:process { siginh rlimitinh noatsecure }; #============= rpcbind_t ============== allow rpcbind_t self:udp_socket listen; #============= rpcd_t ============== allow rpcd_t self:udp_socket listen; #============= setroubleshootd_t ============== allow setroubleshootd_t rpm_var_lib_t:file write; allow setroubleshootd_t rpm_var_lib_t:dir write; #============= sshd_t ============== allow sshd_t chkpwd_t:process { siginh rlimitinh noatsecure }; #============= system_dbusd_t ============== allow system_dbusd_t setroubleshootd_t:process { siginh rlimitinh noatsecure }; #============= unconfined_t ============== allow unconfined_t self:process execmem; #============= audisp_t ============== allow audisp_t var_log_t:file { create open read write execute execute_no_trans getattr }; allow audisp_t var_log_t:dir { write add_name }; allow audisp_t auditd_etc_t:dir { read search open }; allow audisp_t auditd_etc_t:file { read open getattr }; allow audisp_t auditd_log_t:dir { read search open }; allow audisp_t auditd_log_t:file { read open getattr }; allow audisp_t urandom_device_t:chr_file { read open getattr };