Abstract
| Goal |
Improve security and confinement between processes by using SELinux and advanced SELinux techniques and analysis. |
| Sections |
|
| Lab |
|
Configure SELinux in enforcing mode on a server that has been running with SELinux disabled.
SELinux can work in one of three modes: enforcing, permissive, and disabled.
Enforcing
In this mode, SELinux enforces the currently loaded security policy on the system. SELinux logs attempted SELinux access violations and protects the system from them. This mode is the default, and Red Hat recommends that you use it.
Permissive
In permissive mode, SELinux does not block access violations. However, SELinux is still enabled and it otherwise operates according to the loaded security policy; it assigns SELinux labels to files, ports, and processes as usual, and SELinux access violations are logged.
Disabled
SELinux can be disabled. When it is disabled, nothing enforces the SELinux policy, and SELinux labels are not assigned to new files, to ports, or to processes. This mode can make it difficult to enable SELinux in the future. Disabled mode is strongly discouraged.
Use the getenforce command to display the SELinux mode that is in effect.
[root@host ~]# getenforce
EnforcingUse the setenforce command to switch between the enforcing and permissive modes.
Changes made with the setenforce command do not persist across reboots.
[root@host ~]#setenforceusage: setenforce [ Enforcing | Permissive | 1 | 0 ] [root@host ~]#setenforce 0[root@host ~]#getenforcePermissive [root@host ~]#setenforce 1[root@host ~]#getenforceEnforcing
To persistently set the mode at boot time, edit the /etc/selinux/config configuration file.
# 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. # See also: # https://docs.fedoraproject.org/en-US/quick-docs/getting-started-with-selinux/#getting-started-with-selinux-selinux-states-and-modes # # NOTE: In earlier Fedora kernel builds, SELINUX=disabled would also # fully disable SELinux during boot. If you need a system with SELinux # fully disabled instead of SELinux running with no policy loaded, you # need to pass selinux=0 to the kernel command line. You can use grubby # to persistently set the bootloader to boot with selinux=0: # # grubby --update-kernel ALL --args selinux=0 # # To revert back to SELinux enabled: # # grubby --update-kernel ALL --remove-args selinux # SELINUX=enforcing # SELINUXTYPE= can take one of these three values: # targeted - Targeted processes are protected, # minimum - Modification of targeted policy. Only selected processes are protected. # mls - Multi Level Security protection. SELINUXTYPE=targeted
When SELinux is disabled, SELinux policy is not loaded at all; the security policy is not enforced and Access Vector Cache (AVC) messages are not logged. Therefore, all the benefits of running SELinux are lost.
If you choose not to use enforcing mode, then Red Hat strongly recommends that you use permissive mode instead of disabling SELinux.
Install the grubby package:
[root@host ~]# dnf install grubby
...output omitted...Configure your bootloader to add the selinux=0 parameter to the kernel command line:
[root@host ~]# grubby --update-kernel ALL --args selinux=0After reboot, confirm that the getenforce command returns the Disabled output:
[root@host ~]# getenforce
DisabledWhen your systems have been running with SELinux disabled and you want to enable SELinux, you must proceed with care to avoid having problems booting the system or executing normal application operations.
When systems run SELinux in permissive mode, users and processes might label various file-system objects incorrectly. File-system objects that are created when SELinux is disabled are not labeled at all. This behavior causes problems when changing to enforcing mode because SELinux relies on file-system objects being correctly labeled.
To prevent incorrectly labeled and unlabeled files from causing problems, SELinux automatically relabels file systems when changing from the disabled state to permissive or enforcing mode.
Before rebooting the system for relabeling, ensure that the system boots in permissive mode, for example by using the enforcing=0 kernel option.
This mode prevents the system from failing to boot in case the system contains unlabeled files that are required by the systemd daemon before it starts the selinux-autorelabel service.
The following steps provide an overview of how to successfully enable SELinux on a system that has been operating with SELinux disabled.
Configure SELinux to use permissive mode by editing the /etc/selinux/config file.
...output omitted...
SELINUX=permissive
...output omitted...Use the grubby command to remove the selinux kernel parameter if it is present.
If this parameter is present, then this configuration is probably how SELinux was disabled.
[root@host ~]# grubby --update-kernel ALL --remove-args selinuxReboot the system to apply the changes. Check for SELinux denial messages.
[root@host ~]#ausearch -m AVC,USER_AVC,SELINUX_ERR,USER_SELINUX_ERR -ts recent<no matches> [root@host ~]#journalctl -t setroubleshoot-- No entries --
Ensure that files are relabeled upon the next reboot.
The fixfiles command -F option creates the /.autorelabel file.
[root@host ~]# fixfiles -F onboot
System will relabel on next bootReboot the system after running the fixfiles command.
Check for SELinux denial messages again, and fix any that remain.
If there are no denials, then switch to enforcing mode in the /etc/selinux/config file.
...output omitted...
SELINUX=enforcing
...output omitted...Reboot the system to apply the changes. After the system reboots, confirm that the system still works correctly.
[root@host ~]# getenforce
EnforcingAs you prepare to move your system from permissive to enforcing mode, you might need to resolve various SELinux access violations so that your applications and the system continue to operate correctly. There are a number of things that you might need to do before putting the system in SELinux enforcing mode.
When SELinux denies access to a resource, it also logs an Audit event.
If the auditd service is started, then the system logs SELinux Audit events in the /var/log/audit/audit.log file.
Otherwise, the system sends SELinux messages to the /var/log/messages file.
In Red Hat Enterprise Linux, the audit package is installed by default unless you explicitly remove it from the package selection during installation.
The following example extracts the SELinux denials from the Audit log file:
[root@host ~]#grep denied /var/log/audit/audit.log...output omitted... type=AVC msg=audit(1698377265.596:217): avc:denied{ getattr } for pid=27484 comm="httpd" path="/webserver/index.html" dev="vda4" ino=9393827 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
You can also use the ausearch command to verify log events for SELinux.
The ausearch command -m AVC and -ts boot options filter the output to display only messages from SELinux, and from the last system boot.
With the -ts option, you can use the recent and today parameters to display only messages from the last 10 minutes, or from midnight.
[root@host ~]#ausearch -m AVC -ts boot---- time->Mon Oct 30 06:32:56 2023 type=PROCTITLE msg=audit(1698661976.435:87): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44 type=SYSCALL msg=audit(1698661976.435:87): arch=c000003e syscall=262 success=no exit=-13 a0=ffffff9c a1=564301854b70 a2=7fcac87f78b0 a3=0 items=0 ppid=796pid=830auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd"exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null) type=AVC msg=audit(1698661976.435:87): avc:denied { getattr }for pid=830 comm="httpd"path="/webserver/index.html" dev="vda4" ino=8412944 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0 ---- time->Mon Oct 30 06:32:56 2023 type=PROCTITLE msg=audit(1698661976.435:88): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44 type=SYSCALL msg=audit(1698661976.435:88): arch=c000003e syscall=262 success=no exit=-13 a0=ffffff9c a1=564301854c48 a2=7fcac87f78b0 a3=100 items=0 ppid=796pid=830auid=4294967295 uid=48 gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=4294967295 comm="httpd"exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null) type=AVC msg=audit(1698661976.435:88): avc:denied { getattr }for pid=830 comm="httpd"path="/webserver/index.html" dev="vda4" ino=8412944 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
The previous output shows two Audit events with an AVC Audit record.
Both events have the 830 PID, and they are attempts to access the /webserver/index.html file with the /usr/sbin/httpd daemon.
SELinux blocked the getattr attempt on that file.
In enforcing mode, unlabeled files or mislabeled context types might cause problems with accessing files or directories.
The httpd process has the httpd_t SELinux domain, and the httpd process is trying to read a file of the default_t type.
Usually, a newly created file inherits the context of its parent directory.
The following example shows the context of the /etc/httpd/conf.d directory:
[root@host ~]#ls -Zd /etc/httpd/conf.d/system_u:object_r:httpd_config_t:s0 /etc/httpd/conf.d/ [root@host ~]#touch /etc/httpd/conf.d/test_conf[root@host ~]#ls -Z /etc/httpd/conf.d/test_confunconfined_u:object_r:httpd_config_t:s0 /etc/httpd/conf.d/test_conf
In addition, the SELinux policy has other file context rules that help to ensure that files are assigned the correct labels when the files are created. Therefore, you rarely need to change directory or file contexts manually.
Sometimes, however, files get the wrong label, or you create a custom directory for your application that requires the correct context. In those situations, you must relabel the files and directories.
The following log message is a typical SELinux denial due to a mislabeled file.
[root@host ~]#ausearch -m AVC,USER_AVC...output omitted... type=AVC msg=audit(1698377265.596:217): avc:denied{ getattr } for pid=27484 comm="httpd" path="/webserver/index.html" dev="vda4" ino=9393827 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0
The message gives the name, the PID of the process, the path, the device, and the inode of the file or directory that the process tries to access.
The tclass attribute specifies the type of the targeted object, which is either a file or a directory.
The scontext attribute, or source context, is the context of the process, and tcontext, or target context, is the actual context of the file or directory.
This message indicates that SELinux denies the httpd process, whose PID is 27484 and whose domain is httpd_t, access to the /webserver/index.html file, whose inode number is 9393827 on the vda4 device, and with the default_t context type.
When you run the fixfiles -F command and reboot the system, the files on the system are relabeled based on the SELinux policy's file context rules.
File context rules already exist in SELinux for the standard system files and directories.
However, sometimes your application might have its own custom files in nonstandard locations, and you might need to add your own custom file context rules to ensure that the files are automatically relabeled correctly.
The following example lists the file context rules that exist.
[root@host ~]# semanage fcontext -l
...output omitted...
/var/www(/.*)? all files system_u:object_r:httpd_sys_content_t:s0
...output omitted...Rules use extended regular expressions to specify the path and file names.
The most common extended regular expression is (/.*)?, which means "optionally, match a / directory followed by any number of characters".
The regular expression matches the directory listed before the expression and everything in that directory recursively.
When you create a custom directory for your application, you must also add a rule.
To add a new rule, use the semanage fcontext -a command.
The restorecon command -v option lists the relabeled files.
The -R option recursively restores the contexts on directories.
With the restorecon command, you do not specify the context to apply.
The command uses rules in the SELinux policy to determine the context of the file.
[root@host ~]#mkdir /virtual/[root@host ~]#touch /virtual/index.html[root@host ~]#ls -Zd /virtual/unconfined_u:object_r:default_t:s0 /virtual/ [root@host ~]#ls -Z /virtual/index.htmlunconfined_u:object_r:default_t:s0 /virtual/index.html [root@host ~]#semanage fcontext -a -t httpd_sys_content_t '/virtual(/.)?'* [root@host ~]#restorecon -Rv /virtual/Relabeled /virtual from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0 Relabeled /virtual/index.html from unconfined_u:object_r:default_t:s0 to unconfined_u:object_r:httpd_sys_content_t:s0 [root@host ~]#ls -Zd /virtual/unconfined_u:object_r:httpd_sys_content_t:s0 /virtual/ [root@host ~]#ls -Z /virtual/index.htmlunconfined_u:object_r:httpd_sys_content_t:s0 /virtual/index.html
Whenever a process tries to listen on a port, SELinux verifies whether the label that is associated with that process, the domain, is allowed to bind to that port label. This port label stops a rogue service from taking over ports that are otherwise used by other legitimate network services.
If you run a service on a nonstandard port, then you must update the SELinux port labels.
For example, to control access to the 22 TCP port that is used by the ssh service, the port must use the ssh_port_t label.
By default, some ports are labeled with a type that you can use.
For example, a web server might use the 8080 TCP port, which by default has the http_cache_port_t label.
[root@host ~]# semanage port -l | grep 8080
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010The following log message is a typical SELinux denial due to a mislabeled port.
[root@host ~]# ausearch -m AVC,USER_AVC
...output omitted...
type=AVC msg=audit(1698380012.436:267): avc: denied { name_bind } for pid=28420 comm="httpd" src=3131 scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:object_r:unreserved_port_t:s0 tclass=tcp_socket permissive=0The message provides the name and PID of the process, and the port that the process tries to access.
The tclass attribute specifies the type of the targeted object: a TCP socket in this example.
The src attributes indicates the port number.
SELinux denies the name_bind system operation.
To fix such mislabeling issues, use the semanage port -a command.
[root@host ~]#semanage port -a -t http_port_t -p tcp 3131[root@host ~]#semanage port -l | grep 3131http_port_t tcp 3131, 80, 81, 443, 488, 8008, 8009, 8443, 9000
SELinux Booleans are switches that change the behavior of the SELinux policy. These Booleans enable or disable sets of SELinux access rules. Booleans can be used by security administrators to selectively adjust the policy. You might need to set a Boolean to a particular value to allow processes in a specific SELinux domain to work with files of a certain SELinux type, for example.
Use the getsebool command to display SELinux Booleans, and the setsebool command to modify SELinux Booleans.
The setsebool -P command updates the SELinux policy to make the modification persistent.
[root@host ~]#getsebool -aabrt_anon_write --> off abrt_handle_event --> off abrt_upload_watch_anon_write --> on ...output omitted... [root@host ~]#getsebool httpd_enable_homedirshttpd_enable_homedirs --> off [root@host ~]#setsebool -P httpd_enable_homedirs on[root@host ~]#getsebool httpd_enable_homedirshttpd_enable_homedirs --> on
In permissive mode, SELinux logs the access that it must deny, but allows the access anyway.
Switching the system into permissive mode, perhaps to debug a specific process, might have security consequences, because all the other services are now also unprotected by SELinux.
When migrating a system from disabled to enforcing mode, you must resolve AVC issues for all except one or two SELinux domains.
You can keep your system in enforcing mode and only set a specific domain or domains to permissive mode.
This allows you to protect most of the system with SELinux, but the services using that permissive domain would not be protected by SELinux.
Use the semanage permissive -a command to set a specific domain to <domain>permissive mode.
The following command sets the Apache default_t domain to permissive mode.
[root@host ~]# semanage permissive -a default_tUse the semanage permissive -l command to list the domains that are in permissive mode.
[root@host ~]#semanage permissive -lBuiltin Permissive Types mptcpd_t rshim_t Customized Permissive Typesdefault_tinsights_client_t rhcd_t
Use the semanage permissive -d command to switch a domain back to <domain>enforcing mode.
The following command changes the default_t domain to enforcing mode.
[root@host ~]# semanage permissive -d default_t
libsemanage.semanage_direct_remove_key: Removing last permissive_default_t module (no other permissive_default_t module exists at another priority).RHEL System Roles is a collection of Ansible roles and modules that provide a consistent configuration interface to remotely manage multiple systems.
The selinux System Role enables the following actions:
Cleaning local policy modifications related to SELinux Booleans, file contexts, ports, and logins.
Setting SELinux policy Booleans, file contexts, ports, and logins.
Restoring file contexts on specified files or directories.
Managing SELinux modules.
For a detailed reference on the selinux role variables, install the rhel-system-roles package, and see the README.md or README.html files in the /usr/share/doc/rhel-system-roles/selinux/ directory.
The /usr/share/doc/rhel-system-roles/selinux/example-selinux-playbook.yml example playbook installed by the rhel-system-roles package demonstrates how to set the targeted policy in enforcing mode.
The playbook also applies several local policy modifications and restores file contexts in the /tmp/test_dir/ directory.
---
- name: Manage SELinux policy example
hosts: all
vars:
# Use "targeted" SELinux policy type
selinux_policy: targeted
# Set "enforcing" mode
selinux_state: enforcing
# Switch some SELinux booleans
selinux_booleans:
# Set the 'samba_enable_home_dirs' boolean to 'on' in the current
# session only
- {name: 'samba_enable_home_dirs', state: 'on'}
# Set the 'ssh_sysadm_login' boolean to 'on' permanently
- {name: 'ssh_sysadm_login', state: 'on', persistent: 'yes'}
# Map '/tmp/test_dir' and its subdirectories to the 'user_home_dir_t'
# SELinux file type
selinux_fcontexts:
- {target: '/tmp/test_dir(/.*)?', setype: 'user_home_dir_t', ftype: 'd'}
# Restore SELinux file contexts in '/tmp/test_dir'
selinux_restore_dirs:
- /tmp/test_dir
# Map tcp port 22100 to the 'ssh_port_t' SELinux port type
selinux_ports:
- {ports: '22100', proto: 'tcp', setype: 'ssh_port_t', state: 'present'}
# Map the 'sar-user' Linux user to the 'staff_u' SELinux user
selinux_logins:
- {login: 'sar-user', seuser: 'staff_u', serange: 's0-s0:c0.c1023',
state: 'present'}
# Manage modules
selinux_modules:
# Install the 'localpolicy.cil' module with priority 300
- {path: "localpolicy.cil", priority: "300", state: "enabled"}
# Disable the 'unconfineduser' module with priority 100
- {name: "unconfineduser", priority: "100", state: "disabled"}
# Remove the 'temporarypolicy' module with priority 400
- {name: "temporarypolicy", priority: "400", state: "absent"}
roles:
- rhel-system-roles.selinuxEach SELinux command has a man page.
For example, the man page for the semanage fcontext command is the semanage-fcontext(8) man page, and the semanage port command is documented in the semanage-port(8) man page.
Some domains, such as the httpd_t and sshd_t domains, have dedicated man pages that describe all their types and Booleans.
You can also build the man pages by installing the policycoreutils-devel package and running the sepolicy manpage command with the following options:
-a to build all the man pages.
-d to build the man page of a specific domain.
For example:<domain>
[root@host ~]# sepolicy manpage -d httpd_t
/tmp/apache_selinux.8
/tmp/httpd_selinux.8
-p to create the man pages in a specific directory: for example, in the <path>/usr/share/man/man8 directory.
By default, the sepolicy manpage command generates the man pages in the /tmp directory.
The semanage(8), restorecon(8), getenforce(8), setenforce(8), ausearch(8), grubby(8), getsebool(8), and setsebool(8) man pages
For more information, refer to the Getting Started With SELinux chapter in the Using SELinux guide at https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/using_selinux/getting-started-with-selinux_using-selinux
For more information, refer to the Deploying the Same SELinux Configuration on Multiple Systems chapter in the Using SELinux guide at https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html/using_selinux/deploying-the-same-selinux-configuration-on-multiple-systems_using-selinux