Selinux
This document is written for RHEL based systems
switch on selinux
# show status
$ sestatus
...
SELinux status: enabled
...
Current mode: permissive
Mode from config file: permissive
# check config file
> cat /etc/selinux/config
...
SELINUX=permissive
# switch to 'enforcing' and reboot system
# check status again
$ sestatus
...
SELinux status: enabled
...
Current mode: enforcing
Mode from config file: enforcingNOTE: When switching from disabled to enforcing, the whole filesystem needs to be relabels’d first.
Reason for this is that the folders and files created in disabled mode arn’t labeled yet.
# paste an empty file
> touch /.autorelabel
# or use dedicated cmd, which will creating the file
> fixfiles -F onboot
# reboot systempolicy types
Find policy-type settings in /etc/selinux/config
| Policy | Description |
|---|---|
| Targeted This | Policy applies Access Controls to Proccesses that they are often targeted by attacking. (Default) |
| MLS | Multilevel Security Policy. It implements Bell-LaPadula (BLP) model and possible to apply more complex controls. |
...
SELINUXTYPE=targetedDefault policy on Almalinux 9 is default.
To change the policy-type we need to ensure first that the target policy-file is already installed.
In our case the mls - Multi Level Security protection package:
# install mls policy-file
> dnf -y install selinux-policy-mls
# this will install the 'mls' files in the selinux config folder
> ls -1t /etc/selinux/
...
mls
config
targeted
semanage.confChange SELINUXTYPE= to mls, relabel filesystem and reboot the host.
NOTE: on first try ensure that your
SELINUX=mode is set topermissiveto study logs first
Additional Notes
- The default RHEL/AlmaLinux policy forces MCS with only
s0sensitivity. - MLS enforces the
Bell-La PadulaMandatory Access Model. - No desktop support when using MLS due to missing X-server support.
selinux context
| Attribute | Description |
|---|---|
| SELinux User | Mapped to an SELinux user by policy, for each Linux user. |
| Role | Defines SELinux user roles and controls access to domains via policy (RBAC). |
| Type | Defines process domains and file types (TE). |
| Level | Supports sensitivity:category syntax (MLS/MCS), with options including s0 sensitivity and c0-c1023 categories. |
# show file context using '-Z' option
$ ls -Z /etc/os-release
...
system_u:object_r:etc_t:s0 /etc/os-release| Value | Attribute |
|---|---|
system_u | SELinux User |
object_r | Role |
etc_t | Type |
s0 | Level |
The ‘Z’ option can be set for many programs
# show process context using 'Z' option
$ ps axZ
...
system_u:system_r:kernel_t:s0 2 ? S 0:00 [kthreadd]Some usual SELinux contexts
| Value | Attribute |
|---|---|
unconfined | unconfined process or file, not handled by SELinux |
kernel_t | kernel thread or module |
sysadm_t | system administration tools (e.g. RPM, YUM) |
httpd_t | HTTP server process (Apache, Nginx, etc.) |
var_t | variable files (e.g. /var, /usr/local) |
log_t | log files (e.g. system logs, application logs) |
container_runtime_t | container runtime environment (e.g. Docker) |
sshd_t | SSH daemon process |
booleans
By using SELinux booleans, you can fine-tune your system’s security configuration.
# show booleans, filter 'http'
$ getsebool -a | grep http
...
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off# install 'semanage'
> dnf install policycoreutils-python-utils
# use 'semanage' to describe booleans
$ semanage boolean -l
...
httpd_anon_write (off , off) Allow httpd to anon write
httpd_builtin_scripting (on , on) Allow httpd to builtin scripting
httpd_can_check_spam (off , off) Allow httpd to can check spam
httpd_can_connect_ftp (off , off) Allow httpd to can connect ftpChanging a boolean
We want to allow the boolean httpd_can_network_connect
# get current status
> getsebool httpd_can_network_connect
...
httpd_can_network_connect --> off
# switch boolean off using 'setsebool'
> setsebool -P httpd_can_network_connect on
# or switch boolean off using 'semanage'
> semanage boolean -m httpd_can_network_connect --on
# get status
> getsebool selinuxuser_ping
...
httpd_can_network_connect --> onfile-context handling
First, all file context’s are stored in /etc/selinux/targeted/contexts/files/*
To change a file context we can use chcon or semanage. But using these commands requires a restorecon command as well to save the change.
Lets imagin you saved a certificate file on the server by transfering it to your user directory and move it to /etc/pki/tls/certs.
The filecontext will looks like this: unconfined_u:object_r:user_home_t:s0
This file-context is not allowed to be used as certicicate, we need to add at least the cert_t context.
chcon
| Option | Attribute |
|---|---|
-u | SELinux User |
-r | Role |
-t | Type |
# change file context
> chcon -t cert_t /etc/pki/tls/certs/foo.crt
# save state
> restorecon /etc/pki/tls/certs/foo.crt# change full-context
> chcon \
-u system_u \
-r object_r \
-t cert_t \
/etc/pki/tls/certs/foo.crt# copy context from reference file
> chcon --reference=/foo /barsemanage
# change file context
> semanage fcontext -a -t cert_t /etc/pki/tls/certs/foo.crt
# when changing the context a second time, switch '-a' to '-m'
> semanage fcontext -m -t cert_t /etc/pki/tls/certs/foo.crtport handling
# print services and ports, filter for 'http_port'
> semanage port -l | grep http_port
...
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
# add port to 'http_port'
> semanage port -a -t http_port_t -p tcp 7474
# print services and ports, filter for '7474'
> semanage port -l | grep 7474
...
http_port_t tcp 7474, 3000, 80, 81, 443, 488, 8008, 8009, 8443, 9000log analysis
Trigger AVC
AVC stands for Access Vector Cache.
In SELinux, AVC uses predefined rules called “tecs” (Type Enforcement Policies) to determine whether an access request is allowed or denied.
SELinux’s AVC checks if the request matches any of the predefined rules. If it does, the access is allowed; if not, it’s denied.
# install httpd
> dnf install httpd
# stop webserver
> systemctl stop httpd
# switch httpd listen port to 7575
> sed -i 's/Listen\ 80/Listen\ 7575/g' \
/etc/httpd/conf/httpd.conf
# start webserver
> systemctl start httpd
...
Job for httpd.service failed ...log files
- /var/log/audit/audit.log
- /var/log/messages
debug tools
setroubleshoot-serversealertsedispatchsetroubleshootd
policycoreutils-python-utilsaudit2allowaudit2whychcatsemanage
debug commands
| Action | Effect |
|---|---|
aureport --avc | print auditd messages |
ausearch -m avc | search for avc alerts |
ausearch -m avc -ts today | show for today’s avc alerts |
journalctl -t setroubleshoot | using systemd-journald |
sealert -a /var/log/audit/audit.log | generate nice in detail report, contains hints to handle the alerts |
sealert -l dac41341-6fff-4e1d-a903-9491ec490213 | print details including instruction for action, fetch the uuid from /var/log/messages |
grep 'avc: .denied' /var/log/audit/audit.log | grep for avc denies in /var/log/audit/audit.log |
grep setroubleshoot /var/log/messages | grep for setroubleshoot preventions in /var/log/messages |
deny handling
To allow denied actions we can builf our own policy to spefically allowing them.
policy tools
setools-consolesecheckersediffseinfosesearch
policycoreutils-develsepolgensepolicy
generate policy
To generate a rules created from the audit alerts we can use package policycoreutils-devel
This package holds the sepolicy command which can help to perform the initial steps.
See more details in the RHEL documentation:
manually build
terms
.te type enforcement file: A plain text file contains SELinux policy rules.
.mod module file: A binary modul generated from the .te file.
.pp policy package file: The final policy to apply generated from the .mod file.
# define the target eg. `ssh`
> p=ssh
# View AVC denials and pipe them through `audit2allow -l`
> grep $p /var/log/audit/audit.log |\
audit2allow -l
# Same as above but generating the `.te` type enforcement file.
> grep $p /var/log/audit/audit.log |\
audit2allow -l -v -m local_$p > local_$p.te
# Build a binary module `.mod` from the type enforcement file.
> checkmodule -M -m -o local_$p.mod local_$p.te
# Build the `.pp` policy package from the `.mod` file
> semodule_package -o local_$p.pp -m local_$p.mod
# Install the new `.pp` policy module
> semodule -v -i local_$p.ppSometimes multiple iterations of starting the application and running the policy commands are required to get the final result.
There is already a script available.
disable selinux
beside of switching the mode in /etc/selinux/config to disable its also possible to modify boot parameters:
# disbale selinux and reboot
> grubby --update-kernel ALL --args selinux=0
# re-enable selinux and reboot
> grubby --update-kernel ALL --remove-args selinuxlinks
https://www.youtube.com/watch?v=_WOKRaM-HI4 https://github.com/SELinuxProject/selinux-testsuite https://www.linuxtopia.org/online_books/rhel6/rhel_6_selinux/
https://www.server-world.info/en/note?os=AlmaLinux_9&p=selinux&f=8 https://www.server-world.info/en/note?os=AlmaLinux_9&p=selinux&f=1
https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/9/html/using_selinux/writing-a-custom-selinux-policy_using-selinux#creating-and-enforcing-an-selinux-policy-for-a-custom-application_writing-a-custom-selinux-policy
https://access.redhat.com/articles/6999267
https://www.thegeekstuff.com/2017/07/chcon-command-examples/
docker volumes :z podman volumes :z|:Z
auditd | rsyslog
The logging behaviour is different when auditd is running or not