====== SELinux ====== This document applies to Fedora 29. But, all should work on CentOS/REL 7. ===== General ===== Before you can work with all the selinux tools, you must install the following packages first: dnf -y install python3-policycoreutils policycoreutils-python-utils policycoreutils setroubleshoot-server setools-console libselinux-utils coreutils ==== File contexts ==== * List of all selinux contexts (detailed): semanage fcontext -l |**Note:**|''%%seinfo%%'' is part of ''%%setools-console%%'' rpm package.| * List only the contexts: seinfo -t Types: 4840 NetworkManager_etc_rw_t NetworkManager_etc_t NetworkManager_exec_t NetworkManager_initrc_exec_t NetworkManager_log_t ... |**Note:**|You should grep for a context, or pipe into ''%%less%%''!| * List all selinux users: seinfo -u Users: 8 guest_u root staff_u sysadm_u system_u unconfined_u user_u xguest_u * List all selinux user roles: seinfo -r Roles: 14 auditadm_r dbadm_r guest_r logadm_r nx_server_r object_r secadm_r staff_r sysadm_r system_r unconfined_r user_r webadm_r xguest_r The ''%%semanage%%'' command has tree switches: * ''%%-a%%'': add the context * ''%%-m%%'': modify the context * ''%%-d%%'': deletes the context Next, a few examples for managing context using ''semanage'' command: * Change a filecontext for one file: semanage fcontext -a -t httpd_sys_rw_content_t -f f 'test' * Change a filecontext for one directory: semanage fcontext -a -t httpd_sys_rw_content_t -f d 'test' * Change a filecontext for files recursivly: semanage fcontext -a -t httpd_sys_rw_content_t -f f 'test(/.*)?' * Change a filecontext for one directory: semanage fcontext -a -t httpd_sys_rw_content_t -f d 'test(/.*)?' Here, I show some examples for the regex: * ''%%'test/(one|two)(/.)?'%%'' : This would match ''%%test/one/%%'' and ''%%test/two/*%%'', but, not more recursive * ''%%/opt/zendto/'(/.)?'%%'' : This matches everything in ''%%/opt/zendto/%%'' directory, but, not more recursive To recuresively apply the context permanently, use this command: * Make it recuresive permanent: restorecon -R -v test |**Note:**|Usually it’s not a bad idea to use the ''%%-v%%'' switch, this shows, what it changes.| * If you want to apply the context permanently only to the given file/folder, you can do it without ''%%-R%%'' option: restorecon test ==== Boleans ==== Boleans are general values, they are valid for the whole system. * List of all selinux boleans: getsebool -a |**Note:**|Use ''%%grep%%'' or pipe into ''%%less%%''!| * Allow the webserver to connect to other web servers: setsebool -P httpd_can_network_connect true ==== Labeling ==== All changes, which where not saved, using ''%%restorcon%%'' command, will be lost, when you run a relabeling! * Make sure the changes you made survive a relabeling: restorecon -R /www * It is possible to relabel a file system using the fixfiles command, or to relabel based on the RPM database. Use the following command to relabel a file system only using the fixfiles command: fixfiles relabel * Use the following command to relabel a file system based on the RPM database: fixfiles -R restore ||If you have to relable the system, just create ''%%/.autorelabel%%'' file and reboot the server.| * Prepare auto relabeling during boot: touch /.autorelabel |**Note:**|Before reboot, make sure selinux is in permissive mode! System does not always reboot after enforcing SELINUX.| * Make sure the relabeling is set to permissive to allow the relabeling during boot: touch /.autorelabel grep '^SELINUX' /etc/sysconfig/selinux SELINUX=permissive SELINUXTYPE=targeted reboot * If the server fails to boot, put in the end of the follwing line in grub2 prompt: linux16 ... rd.break enforcing=0 |**Note:**|''%%rd.break%%'' asks for a break at an early stage of the boot process. ''%%enforcing=0%%'' puts the system into SELinux Permissive mode. Don’t confuse with ''%%selinux=0%%'' that completely disables SELinux.| ==== Analize autid log ==== * Audit the audit log (in general): cat /var/log/audit/audit.log | audit2why * Unordered List Itemor more speicific for example for the ''%%httpd%%'' service: grep httpd /var/log/audit/audit.log |audit2why * Label the changes you made with ''semanage'': cat /var/log/audit/audit.log | audit2allow * You can also use the ''sealert'' command to get a report of all problems related to ''selinux''. But, you have to install first following package (on CentOS, RHEL or Fedora distributions): dnf -y install setroubleshoot-server sealert -a /var/log/audit/audit.log * This gives, as an example, following result: 100% done found 1 alerts in /var/log/audit/audit.log -------------------------------------------------------------------------------- SELinux is preventing logrotate from map access on the file /etc/logrotate.d/mariadb. ***** Plugin restorecon (92.2 confidence) suggests ************************ If you want to fix the label. /etc/logrotate.d/mariadb default label should be etc_t. Then you can run restorecon. The access attempt may have been stopped due to insufficient permissions to access a parent directory in which case try to change the following command accordingly. Do # /sbin/restorecon -v /etc/logrotate.d/mariadb ***** Plugin catchall_boolean (7.83 confidence) suggests ****************** If you want to allow domain to can mmap files Then you must tell SELinux about this by enabling the 'domain_can_mmap_files' boolean. Do setsebool -P domain_can_mmap_files 1 ***** Plugin catchall (1.41 confidence) suggests ************************** If you believe that logrotate should be allowed map access on the mariadb file 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: # ausearch -c 'logrotate' --raw | audit2allow -M my-logrotate # semodule -X 300 -i my-logrotate.pp Additional Information: Source Context system_u:system_r:logrotate_t:s0-s0:c0.c1023 Target Context unconfined_u:object_r:mysqld_etc_t:s0 Target Objects /etc/logrotate.d/mariadb [ file ] Source logrotate Source Path logrotate Port Host Source RPM Packages Target RPM Packages mariadb-server-10.3.11-1.fc29.x86_64 Policy RPM selinux-policy-3.14.2-47.fc29.noarch Selinux Enabled True Policy Type targeted Enforcing Mode Enforcing Host Name danweb2 Platform Linux danweb2 4.20.3-200.fc29.x86_64 #1 SMP Thu Jan 17 15:19:35 UTC 2019 x86_64 x86_64 Alert Count 1 First Seen 2019-02-08 03:19:01 CET Last Seen 2019-02-08 03:19:01 CET Local ID 17b1c2f9-04fa-43c8-b799-9221390e3fa6 Raw Audit Messages type=AVC msg=audit(1549592341.516:621241): avc: denied { map } for pid=19834 comm="logrotate" path="/etc/logrotate.d/mariadb" dev="dm-0" ino=2494230 scontext=system_u:system_r:logrotate_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:mysqld_etc_t:s0 tclass=file permissive=0 Hash: logrotate,logrotate_t,mysqld_etc_t,file,map ===== Setup ===== * Unordered List ItemYou need to install the following package: yum install setools-console setroubleshoot-server setroubleshoot-plugins policycoreutils-python-utils * Unordered List ItemCheck, what state has ''%%selinux%%'': getenforce ===== Example applications ===== ==== Nginx Proxy ==== * Per default, ''%%selinux%%'' does not allow proxy connections to other hosts, you can enable this: setsebool -P httpd_can_network_connect true * To get a list of all boleans, you can use the ''%%getsebol -a%%'' command: getsebool -a |grep http httpd_anon_write --> off httpd_builtin_scripting --> on httpd_can_check_spam --> off httpd_can_connect_ftp --> off httpd_can_connect_icinga2_api --> on httpd_can_connect_ldap --> off httpd_can_connect_mythtv --> off httpd_can_connect_zabbix --> off httpd_can_manage_icingaweb2_config --> on 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_can_write_icinga2_command --> on httpd_dbus_avahi --> off httpd_dbus_sssd --> off httpd_dontaudit_search_dirs --> off httpd_enable_cgi --> on httpd_enable_ftp_server --> off httpd_enable_homedirs --> off httpd_execmem --> off httpd_graceful_shutdown --> off httpd_manage_ipa --> off httpd_mod_auth_ntlm_winbind --> off httpd_mod_auth_pam --> off httpd_read_user_content --> off httpd_run_ipa --> off httpd_run_preupgrade --> off httpd_run_stickshift --> off httpd_serve_cobbler_files --> off httpd_setrlimit --> off httpd_ssi_exec --> off httpd_sys_script_anon_write --> off httpd_tmp_exec --> off httpd_tty_comm --> off httpd_unified --> off httpd_use_cifs --> off httpd_use_fusefs --> off httpd_use_gpg --> off httpd_use_nfs --> off httpd_use_openstack --> off httpd_use_sasl --> off httpd_verify_dns --> off mysql_connect_http --> off named_tcp_bind_http_port --> off prosody_bind_http_port --> off * For example, if you need to connect an ''%%ldap%%'' server or a ''%%mysql%%'' database from a web application, you should set this boleans to true: setsebool -P httpd_can_network_connect_db true setsebool -P httpd_can_connect_ldap true ==== HTTP ==== For example the Bolt CMS requires to write files in the in ''%%public%%'', ''%%cache%%'' and ''%%config%%'' folders. But, ''%%selinux%%'' does not allow this per default. * Copy the attributes from apache default webroot directory: chcon -t httpd_sys_rw_content_t /var/www/ds/app/cache -R * For the bolt setup, you can replace the base directory variable: base="/var/www" d=ds # make sure the httpd sys context is setup properly: semanage fcontext -a -t httpd_sys_content_t ${base}/${d}'(/.*)?' restorecon -R ${base}/$d # next folder and file have to be read/write: semanage fcontext -a -t httpd_sys_rw_content_t ${base}/$d/app/cache'(/.*)?' semanage fcontext -a -t httpd_sys_rw_content_t ${base}/$d/app/config'(/.*)?' semanage fcontext -a -t httpd_sys_rw_content_t ${base}/$d/public/files'(/.*)?' semanage fcontext -a -t httpd_sys_rw_content_t ${base}/$d/public/extensions'(/.*)?' semanage fcontext -a -t httpd_sys_rw_content_t ${base}/$d/extensions'(/.*)?' # make all permanent (recuresive) restorecon -R ${base}/$d/app/cache restorecon -R ${base}/$d/app/config restorecon -R ${base}/$d/public/files restorecon -R ${base}/$d/public/extensions restorecon -R ${base}/$d/extensions * It’s also possible to a reference copy of the ''%%selinux%%'' attributes: sudo chcon -R --reference=/usr/share/nginx/html /www * Copy the attributes from ''apache'' default webroot directory: sudo chcon -R --reference=/var/www/html /www |**Note:**|If you want to have those changes to default back, you must execute ''%%restorecon -R /%%''!| * Make labeling changes back to default: restorecon -R /www ==== Icinga ==== If the icinga service does not start after configuring API, you should check the following: * Check, if port 5665 is allowed: semanage port -l | grep 5665 * If empty, you have to configure it: semanage port -a -t icinga2_port_t -p tcp 5665 * Check, if port 5665 is allowed: semanage port -l | grep 5665 ==== Piwik (Matomo) ==== Not yet done ... ==== Configure non-standard ports ==== If you have an application which has not a standart port definition, you can also define a port for a service. * Example for configuring port 8888 for httpd service: semanage port -a -t httpd_port_t -p tcp 8888 ===== Problems during boot ===== ==== Procedure to relabel ==== For a password change, next procedure is probably the easiest. - Interrupt grub startup and type ''%%E%%'' to edit the default boot option - Add at the line where ''%%linux16%%'' is listed first, following ''%%rd.break enforcing=0%%'' - Remount ''%%/sysroot%%'', but writable: ''%%mount –o remount,rw /sysroot%%'' - Do a chroot to ''%%/sysroot%%'': ''%%chroot /sysroot%%'' - Do your changes - You have to relabel the filesystems, just touch ''%%/.autorelabel%%'' in ''%%/sysroot%%'' or reboot and add ''%%autorelabel=1%%'' in grub ==== Boot parameters described ==== * **selinux=0 (Bad idea)** \\ If you want to Disable SELinux entirely. You can boot the system with the ''%%SELINUX=0%%'' kernel parameter. This will cause the kernel to not load any of the SELinux infrastructure. The init scripts will notice that you booted with ''%%SELINUX=0%%'' and will touch /.autorelabel themselves. This will cause the machine to automatically relabel the next time you boot with ''%%SELINUX%%'' enabled. We do this because anytime you are booted with ''%%SELNUX=0%%'' files will not get a label. So the next time the system boots the SELinux would report these files as ''%%file_t%%'' and almost no domains can interfact with a ''%%file_t%%'' (Unlabeled file). Files like ''%%/etc/resolv.conf%%'' get recreated at boot time and probably would get this label and the next time SELinux booted, all heck would break loose. * **enforcing=0** \\ Setting this parameter will cause the machine to boot in permissive mode. If your machine will not boot in enforcing mode, this can allow you to boot it and figure out what is wrong. Sometimes you file system can get so messed up that this parameter is your only option. The nice thing about this option, the system continues to create the labels correctly. The AVC messages that are created via this command can be different then in enforcing mode. There are two differences in enforcing mode, every access denial is reported, in permissive only the first denial is reported. However in Enforcing mode you might get a denial on reading a directory and the app will stop. In permissive mode you would get the same avc message but then you would get an avc for each denial when the app continues reading files in the directory. * **autorelabel=1** \\ This parameter will force the system to relabel. It does the same thing as “touch /.autorelabe; reboot”. Sometimes, if the machines labeling is really bad, you will need to boot in permissive mode in order for the autorelabel to succeed. An example of this is switching from strict to targeted policy. In strict policy shared libraries are labeled as shlib_t while ordinary files in ''%%/lib%%'' directories are labeled lib_t. strict policy only allows confined apps to execute ''%%shlib_t%%''. In targeted policy shlib_t and lib_t are aliases. (Having these files labeled differently is of little security importance and leads to labeling problems in my opinion). So every file in ''%%/lib%%'' directories gets the label ''%%lib_t%%''. When you boot a machine that is labeled for targeted with strict policy the confined apps try to execute lib_t labeled shared libraries so and they are denied. ''%%/sbin/init%%'' tries this and blows up. So booting in permissive mode allows the system to relabel the shared libraries as ''%%shlib_t%%'' and then the next boot can be done in enforcing. ===== Creation of selinux module ===== Sometimes not all rules apply to a application. Then, you need to create your own ''selinux'' module. In this example the ''rrdtool'' binary: - Get information from ''/var/log/audit/audti.log'': p=rrdtool; grep 'comm="'$p /var/log/audit/audit.log | audit2allow -l module local_rrdtool 1.0; require { type httpd_t; type nagios_var_lib_t; class file map; } #============= httpd_t ============== # src="httpd_t" tgt="nagios_var_lib_t" class="file", perms="map" # comm="rrdtool" exe="" path="" #!!!! This avc can be allowed using the boolean 'domain_can_mmap_files' allow httpd_t nagios_var_lib_t:file map; - Create now the module configuration file *.te: p=rrdtool; grep 'comm="'$p /var/log/audit/audit.log | audit2allow -l -v -m local_$p > local_$p.te The result is now ''local_$p.te'' file. - Check now the syntax of the config file: checkmodule -M -m -o local_$p.mod local_$p.te This creates the ''local_$p.mod'' file. - Create now the module for selinux: semodule_package -o local_$p.pp -m local_$p.mod This results in ''local_$p.pp'' selinux module - Activate the module and copy it to ''/usr/share/selinux/targeted'' directory: semodule -v -i local_$p.pp Attempting to install module 'local_rrdtool.pp': Ok: return value of 0. Committing changes: Ok: transaction number 21. cp local_$p.pp /usr/share/selinux/targeted/ It's a good idea to use a prefix for the module name (in my case: ''local_'')! If you want to create a module for more than one binary (because they are part of an application), just use ''audit2allow -a'' to create the module configuration. ===== States of selinux ===== * State of ''selinux'': sestatus SELinux status: enabled SELinuxfs mount: /sys/fs/selinux SELinux root directory: /etc/selinux Loaded policy name: targeted Current mode: permissive Mode from config file: permissive Policy MLS status: enabled Policy deny_unknown status: allowed Memory protection checking: actual (secure) Max kernel policy version: 31 * List all loaded ''selinux'' modules (there are many, use grep!): semodule -l