Scaling Privileged Access for Modern Infrastructure: Real-World Insights
Apr 25
Virtual
Register Today
Teleport logo

Teleport Blog - SELinux, Dragons and Other Scary Things - Dec 13, 2022

SELinux, Dragons and Other Scary Things

by Jakub Nyckowski

selinux

What is SELinux?

If you've ever used Linux, you’ve probably heard about SELinux or Security-enhanced Linux. For a very long time, my interaction with it was just restricted to:


cat file.txt
… access denied
~]# getenforce
Enforcing
~]# setenforce 0
~]# getenforce
Permissive
cat file.txt
.. content

Like many other security solutions, SELinux can sometimes be annoying, and understanding even the basic concepts can change our bigger enemy to our best friend.

A little bit of history

SELinux was originally developed by National Security Agency (NSA) and Red Hat to address flaws in Linux security in Mandatory Access Control (MAC) checking for allowed operations after standard Discretionary Access Controls (DAC). It was first released in Linux Kernel 2.6 in 2000. It is implemented using LSM (Linux Secure Modules). It uses Extended File Attributes to store the access labels. A lot of new terms? Let’s try to break them down.

Discretionary Access Control - DAC

It’s known as users and groups and file permissions in Linux. You log in as a Linux user, access all files you own, and “share” files with different users by belonging to the same group. The root user can do anything. Everyone knows it. The first problem is that the root user has access to anything and can do anything. If for some reason, an attacker gains root access to the machine, they have full control over it. File access could be more secure. An application that runs as a user Bob should have access to private keys belonging to that user. Makes sense? Not really. Most of the time, you want to give access only to one application to give access to read private material. /etc/passwd/ accessed by your email client? The same thing. Discretionary means that a user can pass the permissions to a different user. That allows a careless user or an application to share resources with everyone in the system by setting permission to 777. We will talk about it in a second.

Linux Security Modules - LSM

LSM is an in-kernel framework that interrupts syscalls and executes additional logic before returning the result to the called. LSM was initially added to support SELinux in kernel 2.6, but since then, many other modules as AppArmor, SMACK or BPF, have been added. But why was a new framework needed to make the SELinux and others work? The initial implementation prepared by NSA wouldn’t allow any other module to benefit from the architecture introduced for SELinux. Alternative solutions for syscall monitoring based on ptrace are far from perfect. In out-of-process tracing, all information must be processed asynchronously. If a traced application calls unlink() (syscall used to delete a file), then stopping it after the fact won’t prevent the file from being deleted. Another problem is the Time-Of-Check to Time-Of-Use (TOCTOU) attack that could potentially allow the execution of malicious code without the observer's knowledge. Linux Security Modules allow a more secure way of assuring that all expected rules are being followed.

Extended File Attributes

Extended Files Attributes (also known as XATTR or EA) were added to Linux 2.6. Originally implemented to support Access Control Lists (ACL), their flexible design found usage in many different applications. One of them is SELinux. EAs are associated with file i-node struct. They have fixed size (255 values 64kB each in the latest kernel). Currently many other systems like BSD, macOS or Windows have developed similar solutions.

You can check the file's extended attributes by using getfattr:


~]$ getfattr -d -m ".*" file.txt
# file: file.txt
security.selinux="unconfined_u:object_r:user_home_t:s0"

The above command list all file attributes. As you can see, SELinux-related attributes are stored under security.selinux key. You can also use ls -Z to see only SELinux context:


 ls -Z
unconfined_u:object_r:user_home_t:s0 file.txt

To make it easier to remember many Linux commands, support has been added for -Z to display the SELinux context. Some examples are ps, ls, id, netstat.

SELinux to the rescue

SELinux was created to address all the above problems. It doesn’t aim to replace the DAC, and it’s not enabled by default in all Linux distributions (Ubuntu uses AppArmor and comes with SELinux disabled). SELinux allows restricting processes running as a root (as each process runs in its domain), which can reduce the surface of the attack area. It also allows making more granular rules about who can access what. One user may be assigned to many groups, and each group gives access to a small part of the system.

Missing a bit of context?

We mentioned the SELinux context a few times, but we’ve never explained what it really is. Context is a mapping between a subject (process) and a target (label).


user:role:type:level

For example


unconfined_u:object_r:user_home_t:s0

It’s a convention to add _u postfix to the user, _r to a role, and _t to a type.

User

The SELinux user is mapped to a system user when a new session starts. You can check your current session context by using id -Z.

Role

The role represents the mapping between SELinux process domains or file types and as an SELinux user. SELinux users are allowed to have specific roles, and the role determines which process domains and files can be accessed.

Type

The type is an SELinux file type or SELinux process domain. Types are defined in SELinux policies provided by applications. SELinux can operate in two modes, targeted or MLS/MCS. Most of the systems use the targeted mode, which is also easier to understand, and for that reason, we will focus on it. The targeted mode doesn’t use the level label, as those are only being used in MLS/MCS mode.

Implementation

When the system boots, all policies are loaded into the kernel. Then the kernel's role is to enforce them and prevent all unauthorized access. SELinux can operate in 3 different modes:

  • Enforcing - all rules are enforced, and unauthorized access is blocked
  • Permissive - all rules are checked, and unauthorized access is allowed and logged. This mode is useful for debugging.
  • Disabled - SELinux is disabled.

The diagram below shows the order of execution for each system call. As you can see, everything happens inside the kernel, and the process is sequential.

The important point is that DAC runs before SELinux, so missing file permission prevents SELinux from being triggered.

Let's see some examples of how to use it in practice.

Getting all the tools

This article uses many different tools to interact with SELinux. Most of them are not installed by default in many Linux distributions. To know which package to install, use:


dnf whatprovides <binary_name>                   # CentOS, Fedora, RHEL
apt-files search <binary_name>                   # Ubuntu, Mint, Debian
pacman -F <binary_name>                          # ArchLinux
zypper se --provides --match-exact <binary_name> # Suse

If you're using a different Linux distribution, please consult the documentation.

Enable/disable SELinux

To enable SELinux you can use either setenforce 1 to change it temporarily (the setting will reset after reboot), or to make it permanent, edit /etc/selinux/config and set SELINUX=permissive. This will enable SELinux in the permissive mode. After rebooting, check your logs for potential SELinux errors. If there are no errors, you can change the mode to SELINUX=enforcing. If you see any errors, you can relabel all files on your system by creating .autorelabel file in the root directory and rebooting the machine.

touch /.autorelabel
reboot

Never enable Enforcing mode without making sure that SELinux won't block any critical system applications. Otherwise, your system may not boot.

Disabling SELinux works in a similar way. Just set the SELINUX=permissive or SELINUX=disabled in /etc/selinux/config and reboot your machine.

Baby steps

Before we start playing with SELinux, it would be good to know if SELinux is enabled or how to enable it. You can check the status of your system by using:


$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Memory protection checking:     actual (secure)
Max kernel policy version:      33

When disabled, you will only see:


$ sestatus
SELinux status:                 disabled

You can also use:


$ getenforce
Enforcing

If you need a simple Enforcing, Permissive or Disabled string. It’s useful when you don’t want to parse sestatus output when checking SELinux status in a script, for example.

Useful commands: List users


# semanage user -l

List OS user to SELinux user mapping:


# semanage login -l

List all roles:

seinfo -r

List roles information:


$ seinfo -r user_r -x

You can use the above commands to check SELinux mapping.

Real-life example

The above example is useful for understanding how labels and policies are connected, but how to fix a permission issue on a working system? Let’s look at ssh.


ssh [email protected] -p 22 -o LogLevel=FATAL -o Compression=yes -o DSAAuthentication=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i /home/usr/tmp/private_key -o PreferredAuthentications=publickey
[email protected]: Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).

Permission denied doesn’t tell us a lot. Let's look at the host machine. The first thing to check are permissions on ~/.ssh files. Those files are used by the SSH daemon to verify the key used to log in.


$ ls -la ~/.ssh/
total 4
drwx------. 1 user user  30 Oct 16 22:46 .
drwx------. 1 user user 364 Oct 31 01:42 ..
-rw-------. 1 user user 389 Oct 16 22:46 authorized_keys


Everything looks fine. As you probably already know, SELinux needs to be somehow involved. This is the moment when we should look at some logs. But where does SELinux send all the logs anyway? As in most cases, the answer depends. Most systems send the logs to auditd when this one is enabled.


# ausearch -m AVC --start recent
----
time->Sun Oct 30 22:50:56 2022
type=AVC msg=audit(1667170256.593:737): avc:  denied  { read } for  pid=2538 comm="sshd" name="authorized_keys" dev="vda5" ino=691 scontext=system_u:system_r:sshd_t:s0-s0:c0.c1023 tcontext=unconfined_u:object_r:httpd_log_t:s0 tclass=file permissive=0


So we know that sshd is not allowed to access authorized_keys, but how to fix it? At that point, you probably already know that because almost everything in SELinux is a label, we need to set the correct label on that file. What is the correct label, you may ask? Another tool comes in handy here. semanage allows configuring SELinux policies. It also allows listing all default labels. Here I’m filtering output by ssh as we’re looking for SSH-related labels:


# semanage fcontext -l | grep ssh
…
/home/[^/]+/\.ssh(/.*)?             all files          unconfined_u:object_r:ssh_home_t:s0 
…


Aha! All files in a directory that matches /home/[^/]+/\.ssh(/.*)? ergo /home/user/.ssh/authorized_keys in our case should have ssh_home_t target label set. At that point, we could use chcon to set the label:


$ chcon -t ssh_home_t ~/.ssh/authorized_keys

But SELinux comes with restorecon that makes life even easier.


$ restorecon -R -v ~/.ssh
Relabeled /home/vagrant/.ssh/authorized_keys from unconfined_u:object_r:httpd_log_t:s0 to unconfined_u:object_r:ssh_home_t:s0

Now all default labels should be restored, and we should be able to successfully log in to the machines.

Alternatives

At that point, you’ve probably noticed that SELinux is not a very lightweight solution. That has been the main complaint raised by many people. As a consequence, a few other solutions were introduced as an SELinux alternative. The most popular one, AppArmor, is used in Debian, Ubuntu or OpenSUSE and is also implemented by using LSM. It aims to be more straightforward in configuration and management compared to SELinux but offers a lower security guarantee. SMACK is another alternative. It has been adopted by the automotive industry and operating system Tizen.

Conclusion

SELinux can secure your system if you know how to use it and stop fighting with it. At the end of the day, SELinux should be your ally, not your enemy. I hope this article helped you better understand what SELinux is, some of the design decisions that have been made and how to use it in daily work.

Tags

Teleport Newsletter

Stay up-to-date with the newest Teleport releases by subscribing to our monthly updates.

background

Subscribe to our newsletter

PAM / Teleport