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: enforcing
NOTE: 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 system
policy 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=targeted
Default 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.conf
Change SELINUXTYPE=
to mls
, relabel filesystem and reboot the host.
NOTE: on first try ensure that your
SELINUX=
mode is set topermissive
to study logs first
Additional Notes
- The default RHEL/AlmaLinux policy forces MCS with only
s0
sensitivity. - MLS enforces the
Bell-La Padula
Mandatory 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 ftp
Changing 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 --> on
file-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 /bar
semanage
# 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.crt
port 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, 9000
log 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-server
sealert
sedispatch
setroubleshootd
policycoreutils-python-utils
audit2allow
audit2why
chcat
semanage
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-console
sechecker
sediff
seinfo
sesearch
policycoreutils-devel
sepolgen
sepolicy
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.pp
Sometimes 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 selinux
links
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