Selinux

This document is written for RHEL based systems

switch on selinux

enabling 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.

relabel filesystem
# 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

PolicyDescription
Targeted ThisPolicy applies Access Controls to Proccesses that they are often targeted by attacking. (Default)
MLSMultilevel Security Policy. It implements Bell-LaPadula (BLP) model and possible to apply more complex controls.
/etc/selinux/config
...
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 to permissive 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

AttributeDescription
SELinux UserMapped to an SELinux user by policy, for each Linux user.
RoleDefines SELinux user roles and controls access to domains via policy (RBAC).
TypeDefines process domains and file types (TE).
LevelSupports 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
ValueAttribute
system_uSELinux User
object_rRole
etc_tType
s0Level

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

ValueAttribute
unconfinedunconfined process or file, not handled by SELinux
kernel_tkernel thread or module
sysadm_tsystem administration tools (e.g. RPM, YUM)
httpd_tHTTP server process (Apache, Nginx, etc.)
var_tvariable files (e.g. /var, /usr/local)
log_tlog files (e.g. system logs, application logs)
container_runtime_tcontainer runtime environment (e.g. Docker)
sshd_tSSH daemon process

booleans

By using SELinux booleans, you can fine-tune your system’s security configuration.

show booloeans
# 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
use semanage
# 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

OptionAttribute
-uSELinux User
-rRole
-tType
changing file-context
# change file context
> chcon -t cert_t /etc/pki/tls/certs/foo.crt

# save state
> restorecon /etc/pki/tls/certs/foo.crt
changing full-context
# change full-context
> chcon \
  -u system_u \
  -r object_r \
  -t cert_t \
  /etc/pki/tls/certs/foo.crt
changing context
# copy context from reference file
> chcon --reference=/foo /bar

semanage

changing file-context
# 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.

trigger avc
# 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

ActionEffect
aureport --avcprint auditd messages
ausearch -m avcsearch for avc alerts
ausearch -m avc -ts todayshow for today’s avc alerts
journalctl -t setroubleshootusing systemd-journald
sealert -a /var/log/audit/audit.loggenerate nice in detail report, contains hints to handle the alerts
sealert -l dac41341-6fff-4e1d-a903-9491ec490213print details including instruction for action, fetch the uuid from /var/log/messages
grep 'avc: .denied' /var/log/audit/audit.loggrep for avc denies in /var/log/audit/audit.log
grep setroubleshoot /var/log/messagesgrep 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

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