Introduction to SELinux concepts w/pictures
RHEL 7 SELinux User's & Administrator's Guide
This is great. You should read at least the 1st and 10th chapter of it.
- Introductory Chapter 1 (short link: bit.ly/selinux-guide-rhel7)
- Troubleshooting Chapter 10 (short link: bit.ly/selinux-guide-rhel7-troubleshooting)
Targeted KCS Solutions
Solutions to specific problems.
- How to add custom SELinux filename transition rules in RHEL7
- How to create SELinux dontaudit rules to hide avc denied warnings
- Is there a way to copy the entire SELinux config between machines?
Man pages
Most useful are
man -k semanage
Additional man pages like
httpd_selinux
not installed by default but are available in the selinux-policy-doc packageyum install selinux-policy-doc mandb &>/dev/null man -k _selinux
Note that prior to RHEL 7.3, the man pages were in the selinux-policy-devel package
yum install selinux-policy-devel mandb &>/dev/null man -k _selinux
Checking enforcing/permissive/disabled status
SELinux can be globally disabled via /etc/default/selinux
or the kernel cmdline, requiring a reboot. SELinux can be put into permissive mode in the same way, but that can also be done on the fly without a reboot.
Commands to check status:
sestatus # Show current & config-file status getenforce # Show current status grep ^SELINUX= /etc/selinux/config # Show config-file (permanent) status grep -e enforcing= -e selinux= /etc/default/grub /etc/grub2.cfg # Check for kernel args
Permissive domains
Instead of using setenforce 0
on the whole system when you suspect a problem, switch a particular process domain into permissive mode.
See
man semanage-permissive
and Guide: 10.3.4. Permissive DomainsImmediately & permanently switch a process domain into permissive mode
semanage permissive --add logrotate_t semanage permissive -a httpd_t
Immediately & permanently switch a permissive domain back to enforcing
semanage permissive --del logrotate_t semanage permissive -d httpd_t
Check for permissive domains
semodule -l | grep permissive
Immediately disable all permissive domains (i.e., switch them back to enforcing)
semodule -d permissivedomains
Immediately enable any previously-set permissive domains (i.e., switch them back to permissive)
semodule -e permissivedomains
File labels
Every file gets a label. Policy determines what a process domain can do to files of each label.
See
man semanage-fcontext
and Guide: 10.2.1. Labeling ProblemsSet a file type on a directory
semanage fcontext --add samba_share_t "/path/to/dir(/.*)?" && restorecon -RF /path/to/dir semanage fcontext -a httpd_sys_content_t "/path(/.*)?" && restorecon -RF /path
Create an alternate location (equivalency rule) based on an existing directory (which is useful because it recursively includes rules)
semanage fcontext -a -e /var/www /web && restorecon -RF /web semanage fcontext -a -e /home /our/home && restorecon -RF /our/home
Check what a particular [source] process domain can do to a particular [target] file type
sesearch -CA -s httpd_t -t var_log_t
Network port labels
Policy must explicitly allow confined services specific access to certain network port labels; however, the labels can be changed just as easily as file labels.
See
man semanage-port
and Guide: 10.2.2. How are Confined Services Running?Check for port labels for a particular domain/service
semanage port -l | grep http # Look for http-labeled ports semanage port -l | grep ssh # Look for ssh-labeled ports semanage port -l | grep 3333 # Look for a specific port man httpd_selinux man sshd_selinux sesearch -CA -s httpd_t -c tcp_socket -p name_bind # Look for tcp port types that a particular domain is allowed to bind to
Permanently set labels on network ports
semanage port -a -t http_port_t -p tcp 3333 # Permanently add a label to a specific port semanage port -a -t ssh_port_t -p tcp 2222
Boolean on/off switches
There are many commonly-used configurations that require opening up the default SELinux policy a little, e.g.: allowing webservers to send email or read content from NFS. This can always be done by flipping simple toggles.
See
man semanage-boolean
and Guide: 10.2.2. How are Confined Services Running?Check for booleans for a particular domain
semanage boolean -l | grep httpd man httpd_selinux
Set booleans
setsebool httpd_can_sendmail on # Immediate & temporary setsebool -P httpd_use_nfs on # Permanent & takes a minute to rebuild policy setsebool -P httpd_builtin_scripting=off httpd_tmp_exec=1 # "on" and "1", "off" and "0" all work; equals sign optional unless trying to do multiple booleans at once
Inspect audit AVC records
All SELinux AVC denials get logged by the kernel to audit (assuming auditd
is running) and thus show up in /var/log/audit/audit.log
by default. These can be inspected directly or with ausearch
& aureport
.
See
man ausearch
andman aureport
and Guide: 10.3.5. Searching For and Viewing Denials and Guide: 10.3.6. Raw Audit MessagesUse
aureport
to get a broad overviewaureport -a # Get a report of all AVC denial events aureport -i -a | awk 'NR==4 || NR>5' | column -t # Interpret syscall numbers to names; show in columnized list
Use
ausearch
to drill downausearch -i -m avc # Show all from standard audit.log files ausearch -i -m avc -ts recent # Show last 10 minutes ausearch -i -m avc -ts today -c httpd # Show particular command since midnight ausearch -i -m avc -ts 16:05 -su httpd_t # Show particular source (subject) SELinux context since 16:05 PM
Leverage setroubleshoot to get recommendations
There's an optional setroubleshoot-server
package that will automatically translate audit AVC records into more human-readable syslog messages with actionable recommendations.
See
man sealert
and Guide: 10.3.7. sealert MessagesExample usage
Install and enable
yum install setroubleshoot-server service auditd restart
Note that there's a bug in the
setroubleshoot
packages shipped with RHEL 7.2 and older which makes the sealert command somewhat unusable. Update to the latest version. (See: sealert (from setroubleshoot-server) in RHEL 7 fails with error: failed to connect to server: No such file or directory)Do something that SELinux denies and watch the journal (or
/var/log/messages
) for the logs, e.g.:~]# yum install httpd ... ~]# echo Listen 18888 >/etc/httpd/conf.d/listen18888.conf ~]# systemctl restart httpd Job for httpd.service failed because the control process exited with error code. See "systemctl status httpd.service" and "journalctl -xe" for details. ~]# journalctl _COMM=setroubleshootd -- Logs begin at Tue 2016-08-16 00:28:39 EDT, end at Tue 2016-08-16 00:30:02 EDT. -- Aug 16 00:30:02 a72.example.com setroubleshoot[1463]: SELinux is preventing /usr/sbin/httpd from name_bind access on the tcp_socket port 18888. For complete SELinux messages. run sealert -l 87fea572-9f35-47cc-8c81-eb9e9ae8cad0 Aug 16 00:30:02 a72.example.com python[1463]: SELinux is preventing /usr/sbin/httpd from name_bind access on the tcp_socket port 18888. ***** Plugin bind_ports (92.2 confidence) suggests ************************ If you want to allow /usr/sbin/httpd to bind to network port 18888 Then you need to modify the port type. Do # semanage port -a -t PORT_TYPE -p tcp 18888 where PORT_TYPE is one of the following: http_cache_port_t, http_port_t, jboss_management_port_t, jboss_messaging_port_t, ntop_port_t, puppet_port_t. ***** Plugin catchall_boolean (7.83 confidence) suggests ****************** If you want to allow nis to enabled Then you must tell SELinux about this by enabling the 'nis_enabled' boolean. Do setsebool -P nis_enabled 1 ***** Plugin catchall (1.41 confidence) suggests ************************** If you believe that httpd should be allowed name_bind access on the port 18888 tcp_socket by default. Then you should report this as a bug. You can generate a local policy module to allow this access. Do allow this access for now by executing: # grep httpd /var/log/audit/audit.log | audit2allow -M mypol # semodule -i mypol.pp
Instead of using
journalctl
, you could of course also do something like ...grep sealert /var/log/messages
Execute the suggested
sealert
command to view full details, e.g., from abovesealert -l 87fea572-9f35-47cc-8c81-eb9e9ae8cad0
Another possibility is to use
sealert
to analyze a file, getting recommendations for all AVCs in it (could be any audit.log file from any system)sealert -a /var/log/audit/audit.log | less -S
Confining users
In the standard targeted policy, all users are unconfined; however, you can easily change that. You can start simple with preset users but of course you can get as granular as you want.
See
man semanage-login
andman semanage-user
and Guide: 3.3. Confined and Unconfined Users and Guide: 6. Confining UsersCreate a new user that is mapped to
guest_u
(i.e., no internet, no sudo/su or most other setuid/setgid apps, no X)useradd -Z guest_u newuserbob
Make it so
guest_u
&xguest_u
won't be allowed to execute anything in/tmp
or$HOME
~]# setsebool -P guest_exec_content=off xguest_exec_content=off ~]# semanage boolean -l | grep exec_content auditadm_exec_content (on , on) Allow auditadm to exec content guest_exec_content (off , off) Allow guest to exec content dbadm_exec_content (on , on) Allow dbadm to exec content xguest_exec_content (off , off) Allow xguest to exec content secadm_exec_content (on , on) Allow secadm to exec content logadm_exec_content (on , on) Allow logadm to exec content user_exec_content (on , on) Allow user to exec content staff_exec_content (on , on) Allow staff to exec content sysadm_exec_content (on , on) Allow sysadm to exec content
Confine an existing user, mapping to
user_u
(i.e., no su/sudo or most other setuid/setgid apps)semanage login -a -s user_u existinguseralice
Fix SELinux denials by allowing requested access
This should be a last resort ... done sparingly & with care. The vast majority of problems can be solved by setting proper file labels or tweaking booleans or figuring out that the application/admin is doing something wrong.
See
man audit2allow
and Guide: 10.3.8. Allowing Access: audit2allowExample:
ausearch -i -m avc | grep xxxx | audit2allow