[Illustration] Introduction to SELinux – How it works? Explanation of the Basic knowledge –

What is SELinux?

SELinux , Secure Enhanced Linux , is the module which enhances Linux Kernel security. SELinux watches and controls the Processes to access the Linux Kernel resources.

In principle, SELinux controlls processes to access the all resource managed by OS, but as an implementation, control related to access to the filesystem and use of the TCP/UDP port is centrally set.

In many cases, when receiving a system call from an application, it hooks at the Linux Security Module (LSM) , the kernel function , to check with permission. Since the amount of system calls and the number of allow rules are large, checking is carried out by judging with the cache named AVC to reduce the load.

Some applications that are made conscious of SELinux (SELinux-Aware applications) , can access control using the SELinux library instead of system call. (for example, SE-postgreSQL. There is few app.)

The architectural overview of SELinux is shown below.

SELinux gives a label named "context" to all process and resource managed by OS. Process's context is called "Source Context(scontext)" , and resource accessed by process such as file/dir is called "Target Context".

On the other hand, SELinux's access control rule is called "Access Vector Rules(AV rules)" and it is defined which operation from scontext to tcontext is permitted. If Process's operation is not allowed by AV rules, the operation is denied.

Context format is below.

[ User : Role : Type/Domain : Sensitivity range ]

Third attribute is called "Domain" when labeled to process, and called "Type" when labeled to resource like file/dir, or network. Although they are called differently, basically treated the same.

Scope covered in this article

In this article, I will explain assuming "SELINUX=enforcing, SELINUXTYPE=targeted" which is the default setting of SELinux.

In this mode, Access Vector Rules(AV rules: ACL) deals only Type/Domain, which is the third attriburte of context, and ignore other attribute, User, Role, and Sensitivity range.


Q. Is SELinux effective even with default settings?

A. Yes, it has sufficient effect.

Access Vector Rules(ACL) is created based on general information such as "what kind of directory can httpd process access to concretely?" or "what type of TCP port should she use?"

So, if you do not make any special settings, it should work fine by default.

However, if you change the public directory by httpd from /var/www/html, or change the listen port from tcp:80/443, you need SELinux configuration corresponding to it.

Although less troubles less than before, permission rules (policy rules) as a bug fix still are added by the update.

Q. How many are there policy rules? Do I have to write policies?

A. More than 200,000. But you need not make basically.

There are two major policy rules.

One is Type Enforcement rules (TE rules) , including AV rules mentioned above and Type Transition rules described later , and has rules more than 200,000.

You can check the Type Enforcement rules with the following command.

sesearch --all

If shown "command not found", you should install "setools-console" with yum.
If you want to display only AV rules, you type "sesearch --allow".

Another is Labeling rules which defines "Newly created file/dir under THIS directory is allocated THIS context". This rules have about 6,000 rules. For example, in case there is File Labeling Rule like the following,

/tmp(/.*)?  all files  fileB_u:fileB_r:fileB_t:s0

all kind of file (including symlink, dir, block-device-file, and so on) under /tmp ot /tmp itself is labeled this context(fileB_u:fileB_r:fileB_t:s0). Even if it is not new, the context is restored according to this rule by doing the "restorecon -RFv" command.

Although File Labeling rules is not showned by sesearch command, you can check with following command.

semanage fcontext -l

semanage needs "yum -y install policycoreutils-python" command for install the package.

In the label rules, there are also Network Labeling Rules, which is combined TCP/UDP port to context. You can check this rules with following command.

semanage port -l

Below is an image diagram of the Labeliing Rule (purple places).

Q. Where is SELinux's entity?

A. Configuration is under /etc/selinux and  /var/lib/selinux , and file/dir context are in Extended Attributes of filesystems, binary at runtime is under /sys/fs/selinux

Configuration files of Policy rules is in /etc/selinux and /var/lib/selinux. The basic config file is /etc/selinux/config, and the reference policy, which is as main, is at /etc/selinux/targeted/policy/policy.##.

And, file/dir's context exists in "security.selinux" Extended Attribute which at i-node realm of filesystem. Extended Attribute is displayed with "getfattr" command, and is set with "setfattr".

[root@localhost ~] yum -y install attr
[root@localhost ~] touch test1.txt
[root@localhost ~] getfattr -m security.selinux -d test1.txt
# file: test1.txt
[root@localhost ~] setfattr -n security.selinux -v system_u:object_r:httpd_sys_content_t:s0 test1.txt
[root@localhost ~] getfattr -m security.selinux -d test1.txt
# file: test1.txt

However, normally it is not used "getfattr" or "setfattr", but used "ls -Z" and "chcon".

[root@localhost ~]# ls -Z test1.txt
-rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 test1.txt
[root@localhost ~]# chcon -t httpd_sys_rw_content_t test1.txt
[root@localhost ~]# ls -Z test1.txt
-rw-r--r--. root root system_u:object_r:httpd_sys_rw_content_t:s0 test1.txt

And, if you want to reset as Labeling rule, you can use "restorecon -RFv" command. (R: recursively execute, F: force, v: verbose)

[root@localhost ~]# restorecon -RFv test1.txt
restorecon reset /root/test1.txt context system_u:object_r:httpd_sys_rw_content_t:s0->system_u:object_r:admin_home_t:s0

Q. How many kinds of permissions are there?

A. A lot

You can list all permissions with "seinfo" commad.

[root@localhost ~] yum -y install setools-console
[root@localhost ~] seinfo -c -x

For example, compared with operations for files and networks, the content to be allowed is completely different. There is an operation called reading in the file, but it is not on the network. In other words, the specific content of the operation to be permitted differs depending on the operation target.

The object to be operated is called Object Class, and the content of operation to be permitted is called Permission.

The number of object classes is around 100, and the number of permissions exceeds 1000. See below URL for the detail.

ObjectClassesPerms - SELinux Wiki

Q. What effect can we expect specifically in SELinux eventually?

A. We will look in detail in the next chapter and beyond.

example of httpd

An httpd process is usually started in the domain httpd_t. The context can be confirmed with ps command with "Z" option.

[root@localhost ~] yum -y install httpd
[root@localhost ~] systemctl start httpd
[root@localhost ~]# ps auxZ | grep httpd_t
system_u:system_r:httpd_t:s0    root      1526  0.0  0.1 224024  5024 ?        Ss   23:51   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    1527  0.0  0.0 224024  2956 ?        S    23:51   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    1528  0.0  0.0 224024  2956 ?        S    23:51   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    1529  0.0  0.0 224024  2956 ?        S    23:51   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    1530  0.0  0.0 224024  2956 ?        S    23:51   0:00 /usr/sbin/httpd -DFOREGROUND
system_u:system_r:httpd_t:s0    apache    1531  0.0  0.0 224024  2956 ?        S    23:51   0:00 /usr/sbin/httpd -DFOREGROUND

On the other hand, what rules are applied to "/var/www/html" which is the general location of web server contents?

[root@localhost ~]# semanage fcontext -l | grep /var/www/html
/var/www/html(/.*)?/uploads(/.*)?                  all files          system_u:object_r:httpd_sys_rw_content_t:s0
/var/www/html(/.*)?/wp-content(/.*)?               all files          system_u:object_r:httpd_sys_rw_content_t:s0
/var/www/html(/.*)?/wp_backups(/.*)?               all files          system_u:object_r:httpd_sys_rw_content_t:s0
/var/www/html(/.*)?/sites/default/files(/.*)?      all files          system_u:object_r:httpd_sys_rw_content_t:s0
/var/www/html(/.*)?/sites/default/settings.php    regular file       system_u:object_r:httpd_sys_rw_content_t:s0
/var/www/html/[^/]*/cgi-bin(/.*)?                  all files          system_u:object_r:httpd_sys_script_exec_t:s0
/var/www/html/munin(/.*)?                          all files          system_u:object_r:munin_content_t:s0
/var/www/html/cgi/munin.*                          all files          system_u:object_r:munin_script_exec_t:s0
/var/www/html/munin/cgi(/.*)?                      all files          system_u:object_r:munin_script_exec_t:s0
/var/www/html/owncloud/data(/.*)?                  all files          system_u:object_r:httpd_sys_rw_content_t:s0
/var/www/html/nextcloud/data(/.*)?                 all files          system_u:object_r:httpd_sys_rw_content_t:s0
/var/www/html/configuration.php                   all files          system_u:object_r:httpd_sys_rw_content_t:s0

A rule matching the directory under "/var/www/html" is displayed. Looking at the rule on the directory above,

[root@localhost ~]# semanage fcontext -l | grep /var/www | more
/var/www(/.*)?                                     all files          system_u:object_r:httpd_sys_content_t:s0

it is displayed like this. That is, the content under "/var/www" is labeled "httpd_sys_content_t".

(/.*)? is a regular expression, meaning here refers to all files/dirs under /var/www and /var/www itself.

Then, what kind of operation is permitted from domain "httpd_t" to type "httpd_sys_content_t"?

[root@localhost ~]# sesearch --allow | grep "allow httpd_t httpd_sys_content_t "
   allow httpd_t httpd_sys_content_t : dir { ioctl read getattr lock search open } ;
   allow httpd_t httpd_sys_content_t : lnk_file { read getattr } ;
   allow httpd_t httpd_sys_content_t : file { ioctl read getattr lock open } ;
   allow httpd_t httpd_sys_content_t : dir { ioctl read write getattr lock add_name remove_name search open } ;

Four permission rules (AV rules) are displayed. The first rule is included in the fourth rule. Since permission rules are installed from various modules, duplication often occurs frequently. (So as the number of rules lines increases...)

"lnk_file" is a symbolic link file. "read" means generic file access permission, and "getattr" means access permission to attribute information. Since symbolic link has link destination information in meta (attribute) information, getattr is necessary.

"file" is a general file. "read" and "getattr" are the same as lnk_file. "ioctl" means permission to access functions provided by the IO driver (Disk IO driver in this case). "lock" is exclusive, "open" is to make file I/O (read / write) possible by linking file descriptor.

"dir" is the directory. In addition to file permission, write meaning generic writing to the directory, "add_name" to create files under the directory, "remove_name" to delete files are allowed.

These are operations to files under "/var/www/html" which are given to httpd (However, if it falls under this directory and hits with another File Labeling Rule, another context will be assigned, so operation permission The contents are different.)

Type Transition Rules for determining process domain

By the way, how is it determined that the domain of httpd is "httpd_t"?

Actually, the element that decides process domain is the Type Transition Rules. The execution file of httpd is /usr/sbin/httpd, but the type of this file is httpd_exec_t.

[root@localhost ~]# ls -Z /usr/sbin/httpd
-rwxr-xr-x. root root system_u:object_r:httpd_exec_t:s0 /usr/sbin/httpd

On the other hand, Type Transition Rules have the following rules.

[root@localhost ~]# sesearch --type | grep httpd_exec_t
type_transition init_t httpd_exec_t : process httpd_t;

This means that if a process in the domain called init_t invokes an executable file of type httpd_exec_t, that process will transition to the domain of httpd_t. Because the domain of "systemd" process is "init_t", it matches this rule at startup and when starting httpd service with the systemctl command (since it is activated by operation with systemd).

[root@localhost ~]# ps auxZ | more
LABEL                           USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
system_u:system_r:init_t:s0     root          1  0.0  0.1 193512  6612 ?        Ss   11:30   0:04 /usr/lib/systemd/systemd --switched-root --system --deserialize 22

In the case that does not correspond to this type_transition rule, httpd inherit the domain of the process that started up. For example, the type when the root user is in bash with login or su - is "unconfined_t". This means "no restriction", and as SELinux, it is a type that can operate quite freely. It is determined in advance by the login definition rule, but it is also possible to change the setting so as to lower the authority.

[root@localhost ~]# ps -Z
LABEL                              PID TTY          TIME CMD
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 4152 pts/0 00:00:00 bash

If you run httpd directly (not systemctl) in this state, the context of httpd will also be unconfined_t.

[root@localhost ~]# ps auxZ | grep httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 root 4315 0.0  0.0 224020 3488 ? Ss 22:27   0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 apache 4316 0.0  0.0 224020 2956 ? S 22:27   0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 apache 4317 0.0  0.0 224020 2956 ? S 22:27   0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 apache 4318 0.0  0.0 224020 2956 ? S 22:27   0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 apache 4319 0.0  0.0 224020 2956 ? S 22:27   0:00 /usr/sbin/httpd
unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 apache 4320 0.0  0.0 224020 2956 ? S 22:27   0:00 /usr/sbin/httpd

In here, we can see what SELinux aimed for. That is, an httpd process started with a domain "httpd_t" once, he can not get out of this domain whatever the process is hijacked, promoted to root authority, or a shell is started, and fork the child process (unless matching type_transition rule), so what he can do is limited within the AV rules given to httpd_t, regardless of root. (Caution: If you take over the process of unconfined_t, the SELinux will be useless, so you should never start httpd directly from the login user's shell.)

The answer of the FAQ "I heared it's OK even if a process is hijacked and promoted to root in enabling SELinux, but will not SELinux be invalidated if the process is taken over?" was indicated as above.

Vision of SELinux -DAC and MAC -

As I have already laid the grounds for the answer, SELinux does not aim to prevent the attack itself. The purpse is to place the process under Mandatory Access Control (MAC) and limit the behavior even if the process is compromised or root privilege is taken.

The MAC by SELinux is different from the DAC (Discretely Access Control) of the filesystem up to now.

Since the DAC of the filesystem can be changed by each user, so it is called like this, but there is another reflection that the authorization to root is made too much otherwise.

That is, if you become root, you can become God who freely manipulates the system and decide the law, but due to the vulnerability of the program cracking acts promoting from remote to root have been done many times.

Access control by SELinux can not be changed simply by being root. In order to become God of the system, it needs to be a root authority and domain "unconfined_t".

So as a point, if an attacker is password cracked and logged in by ssh, you can not restrict attacks. What is effective is a story when a process that is running with httpd etc. is hijacked by buffer overflow etc. to the last.

Restrict login user's operation with SELinux

As mentioned above, there is a risk that if you start up from the shell by default, it will run in an unlimited domain called "unconfined_t". This is true even for general users.

To restrict this, you need to change the login domain from unconfined_t. In order to realize this, it is necessary to link "local account user" to "SELinux user (the first attribute of the context)".

The default SELinuix user (__default__) at Linux login is "unconfind_u" user.

[root@localhost ~]# semanage login -l
Login Name           SELinux User         MLS/MCS Range        Service
__default__          unconfined_u         s0-s0:c0.c1023       *
root                 unconfined_u         s0-s0:c0.c1023       *
system_u             system_u             s0-s0:c0.c1023       *

The default value is __default__, and all users are associated with "unconfind_u", and the role of this SELinux user is linked to "unconfined_r".

[root@localhost ~]# semanage user -l
                Labeling   MLS/       MLS/
SELinux User    Prefix     MCS Level  MCS Range                      SELinux Role
guest_u         user       s0         s0                             guest_r
root            user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
staff_u         user       s0         s0-s0:c0.c1023                 staff_r sysadm_r system_r unconfined_r
sysadm_u        user       s0         s0-s0:c0.c1023                 sysadm_r
system_u        user       s0         s0-s0:c0.c1023                 system_r unconfined_r
unconfined_u    user       s0         s0-s0:c0.c1023                 system_r unconfined_r
user_u          user       s0         s0                             user_r
xguest_u        user       s0         s0                             xguest_r

And the domain at login will be partially changed role "_r" to "_t".

Let's actually link "testuser" to a user who is not "unconfined_u".

[root@localhost ~]# semanage login -a -s staff_u testuser
[root@localhost ~]# semanage login -l

Login Name           SELinux User         MLS/MCS Range        Service

__default__          unconfined_u         s0-s0:c0.c1023       *
root                 unconfined_u         s0-s0:c0.c1023       *
system_u             system_u             s0-s0:c0.c1023       *
testuser             staff_u              s0-s0:c0.c1023       *

In this state, "su - testuser" does not change the domain because it is a shell which is originally working with "unconfined_t".

[root@localhost ~]# su - testuser
Last login: Sun Jul  1 21:58:14 JST 2018 on pts/0
[testuser@localhost ~]$ id -Z

Therefore, connect with a new SSH session and log in with testuser. Surely, the domain has changed to staff_t.

[testuser@localhost ~]$ id -Z


Copied title and URL