SEPostgreSQL SELinux Overview
This chapter introduces the overview of SELinux, including its security design, model and facilities to help administration.
- List of chapters
- Introduction
- Architecture
- Specifications
- SELinux Overview
- Administration
- References
- Development
SELinux design and model
The shortest answer to the question of "what is the SELinux?" is that it is an implementation of reference monitor within the Linux kernel. The reference monitor is a small software module to control all the accesses to data objects and devices based on its security policy, which have to be 1) tamperproof, 2) always-invoked and 3) small enough to be verifiable.
At first, please consider the reference monitor model on the most abstracted design layer. In our information systems, all the data objects are managed by something like operating systems, so we have to send the object manager a request to access the object. The object manager performs as an agent of us. It accesses the required data object and returns to the user. In this model, we have three entities here: 1) the data object to be accessed, 2) the subject of the data access and 3) the method to access to the data object.
In the case of operating system, we need to invoke correct system calls, like read(2), to access our target data objects. It also means we can check all the accesses to the data object managed by operating system with monitoring invocations of system calls. SELinux always (even if the request come from root) checks the system calls and makes its decision. If it should be denied, SELinux prevents execution of the system calls any more.
We can port this mode to accesses on database objects. In this case, all the data objects are accessed via SQL, instead of system calls. When we try to run SQL queries, SE-PostgreSQL always acquires them to check the privileges of client, and makes its decision based on the security policy of SELinux. It is fully independent from any existing database acl mechanism.
XACE/SELinux is another example to utilize in-kernel reference monitor from userspace applications. In this case, resources are X-window objects, and X-protocol is a method to access.
See the The privileges of clients. It says SE-PostgreSQL applies the security context of peer process as privileges of client, independently from the database authentication. A same security policy always returns same result for the same combination between two security contexts, so it also means we can apply consistent rules in access controls. In addition, all decisions in access controls are centralized manageable due to the single unified security policy, and non-bypassable even if clients are database superusers due to its characteristics of always-invoked.
The following a few sections describes the details of rules to make a decision.
Security context
This subsection introduces the details of security context again.
See the Management of security context to understand implementation in SE-PostgreSQL.
A security context is an attribute represented in text format, and contains all the information to make a decision in access controls by SELinux. It has four fields separated by colon character, these are "SELinux user", "role", "type" and "range".
SELinux makes its access control decision based on a few different security models, and they adopt individually different field to make its decision. It need all the security models to allow the required accesses to get a positive result.
The first field is "SELinux user" which corresponds to user identifier of the operating system. user_u is a substitute when a proper SELinux user does not defined in the security policy. The second field is "Role" which is used in RBAC. This field is available at only processes, so object_r is uniformly set to any resources. The third field is "Type" or "Domain". We call is as "Domain" when the security context is assigned to process. The type or domain is used as an identifier of type enforcement which is most significant security model in the SELinux. The fourth field is "Range" which is used in MLS (Multi Level Security) or MCS (Multi Category Security) mechanism. This field can be translated into human readable format by mcstrans service. For example, it enables to display s0:c0.c1023 as SystemHigh.
We introduce these security models below.
Type Enforcement
TE (Type Enforcement) is the most significant security model in SELinux. It adopts the third field of security context as its identifier, and we describe the relationship between two types. We can call a type assigned to processes as a domain, but here is no fundamental difference other than its name.
In the following example, the security policy allows a process labeled as postgresql_t to read or write files labeled as postgresql_db_t, and to bind a socket a specific port number labeled as postgresql_port_t. SELinux enforces all the entities which appear on access controls to have a type. The type is an abstraction of its position in access controls, so same result will be returned for the same combination of a domain, a type and actions. In the default security policy, the postgresql server process has postgresql_t domain, the database files stored in /var/lib/pgsql/data/* have postgresql_db_t type, the web contents files stored in /var/www/html/* have httpd_sys_content_t type, and the well-known port number of PostgreSQL has postgresql_port_t type.
This security policy defines two relations. The one is between postgresql_t and postgresql_db_t, and the other is between postgresql_t and postgresql_port_t. The former rule allows postgresql_t domain which contains PostgreSQL server process to read and write files labeled as postgresql_db_t which contains database files. The other rule allows postgresql_t domain to bind a tcp port number labeled as postgresql_port_t which contains the well-known PostgreSQL port (5432). However, there is no explicit rules between postgresql_t domain and httpd_sys_content_t type, so SELinux prevents all accesses between them due to its white list rule.
The actual type enforcement rules are a large set of these rules. However, the recent upstreamed security policy is well moduled, and rich predefined macros and templates will help to understand type enforcement rules.
Domain transition
It is important to understand how to assign a security context of processes, not executable program files. A process inherits the domain of its parent process in the normal cases. However, the /sbin/init is the common ancestor of all the processes. If SELinux had no feature to switch domain of processes, all processes would work same domain. But it is incorrect.
SELinux has a mechanism to switch domain of processes, called as "domain transition".
It replaces the domain of process on execve() system call which kicks a new executable program file. For example, the following policy enables to replace the domain of process labeled as initrc_t into postgresql_t when it executes a program file labeled as postgresql_exec_t.
TYPE_TRANSITION initrc_t postgresql_exec_t : process postgresql_t;
In the default security policy, the initrc_t is a domain for init scripts, and the postgresql_exec_t is a type for /usr/bin/postgres executable file. If there was no TYPE_TRANSITION, PostgreSQL server processes kicked by init script would inherit initrc_t, however, the TYPE_TRANSITION rule enables to change the domain of the process, then it works within postgresql_t domain as we expected.
The /sbin/init works on the init_t domain, so rest of child processes are assigned their proper domain via chains of domain transition.
We can apply this scheme for resources except for processes. The following example uses file as the object class, it means the security context of newly created file under the directory labeled as var_log_t is postgresql_log_t
TYPE_TRANSITION postgresql_t var_log_t : file postgresql_log_t;
This idea is also applied in SE-PostgreSQL, to specify the security context of newly created database objects.
Role Based Access Control
SELinux implements its RBAC (Role Based Access Control) feature as a boundary of domain transitions. The role is a set of domains, and it is identified by the second field of security context. Please note that it is not a set of types. This idea is applied to processes only.
When a process tries to switch its working domain, both of older and newer domain have to be contained the current role. Please note that domain transition replaces the third field in security context of process, but it does not affect the role because it is a different concept independently configured.
When a user assigned a role of foo_r which dominates dom_A_t, dom_B_t and dom_C_t, and his initial domain was dom_A_t, the RBAC policy allows his process to switch its domain to dom_B_t and dom_C_t, but it disallows to switch to dom_X_t even if type enforcement has a rule to translate to the domain.
If a role of baz_r dominates dom_X_t in addition to them, and he is assigned the baz_r role at the login time, the above domain transition will be allowed.
We can use this feature to actualize limited privileged users. For example, we will be able to see a root user with a role of database administration can manage database configuration, start/stop sever process and so on, but he does not touch configurations related to mail server, web server and so on.
However, we have to wait for more improvement in the default security policy to see the vision. So, we don't use the RBAC feature aggressively in the default policy of SE-PostgreSQL,
MLS and MCS
The MLS (Multi Level Security) is a design of traditional mandatory access controls based on the Bell-La-Padulla model. It uses the fourth field in the security context called as range. The MCS (Multi Categories Security) is a simplified design of MLS model.
The range field of processes have two parts separated by a hyphen character (-), but rest of resources have a unique range field. The left-hand of the part is called as a lower-range, and the right-hand of the part is called as a higher-range. In addition, individual range has two elements separated by colon character. The left-hand is a sensitivity level like s0, and the right-hand is categories like c0.c15. SELinux applies the sensitivity on access controls based on the hierarchical relationship, and applies the categories on access controls based on the inclusion relationship.
Any range field have a sensitivity level and zero or more categories. We have a few notation rules for categories. It can be omitted when no categories are associated. It allows to enumerate several categories separated by a comma character, and it especially allows to describe a consecutive categories separated by a period character.
The following example shows a security context of a process, and its range field is s0-s0:c0,c3.c7,c9. It has two parts because the owner of the security context is process. The left-hand is s0, so there is no categories here, and the right-hand is s0:c0,c3.c7,c9, so it has c0, c3, c4, c5, c6, c7 and c9.
[kaigai@saba ~]$ id -Z unconfined_u:unconfined_r:unconfined_t:s0-s0:c0,c3.c7,c9
MLS rules
The access control rules in MLS are described as a relationship between lower- or higher-range of process and range of resources. Which range is checked depends on the domain of the process working on. Some of special domains are configured to apply higher-range in checks of MLS rules, but most of domains apply lower-range there.
When a process with s2:c1.c2-s3:c0.c3 range working on non-special domain tries to read files, SELinux prevents it to read a file labeled as s3:c0:c1 because s3 is higher than s2, and a file labeled as s1:c2.c3 because c3 is not dominated by c1.c2. However, SELinux does not prevent to read a file labeled as s2:c1.c2 and s1:c1.c2 because these are equal or dominated by the lower-range of the process.
When the process tries to write files, SELinux does not allow it except for a file labeled as s2:c1.c2 which is same as lower-range of process.
In summary, the following rules are requirements by MLS policy
- When a process tries to read a resource, its sensitivity has to be equal or lower than the sensitivity of the process.
- When a process tries to read a resource, its categories have to be equal or dominated by the categories of the process.
- When a process tries to write a resource, its range is has to be equal to the lower-range of the process.
MCS rules
The MCS model is a simplified implementation of MLS. It makes all the processes and resources to share a unique sensitivity level, so all sensitivities have equal-relationship, thus, it decides accessibility based on inclusion relationship only.
The lower- and higher-range get different meanings compared to MLS ruls. In MCS rules, the lower-range means the default range when it creates a new resource, and the higher-range means the privileges of the process.
When a process with s0-s0:c1.c2 tries to read or write files, SELinux prevents the action for a file labeled as s0:c0.c1 because c0 is not dominated by c1.c2, but SELinux allows it for a file labeled as s0:c2 and uncategorized.
In the default security policy, MCS rules are activated, and MLS is an option.
SELinux customization
Enforcing and Permissive mode
SELinux has two working modes: enforcing and permissive mode. In the both working modes, SELinux checks its security policy to decide whether the given action should be allowed, or not. However, SELinux does not prevent anything in the permissive mode, but it also generates audit log records to report violated accesses. It can be used to list up what permissions are required by the running applications.
We can put the system default behavior on /etc/selinux/config, and the setenforce command enables us to switch the working mode dynamically.
[kaigai@saba ~]$ cat /etc/selinux/config # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=enforcing
SE-PostgreSQL follows the working mode of in-kernel SELinux in the default. But, we can set up its own working mode by the guc variable of sepostgresql.
Booleans
The boolean feature allows several part of the security policy to be conditional. The boolean is a series of variables managed by SELinux, which has a status either on or off. One or more blocks of rules depend on the boolean, and it allows administrators to set a new value, so it is possible to customize the security policy setting without modification of security policy.
For example, SELinux does not allow Samba file server to access user's home directories in the default. However, conditional policies to allow them depend on the boolean of samba_enable_home_dirs which has false in the default, as follows:
if (samba_enable_home_dirs) { allow smbd_t user_home_t : file { create read write append unlink .... }; allow ambd_t user_home_t : dir { create search add_name remove_name unlink ... }; : : }
So, the Samba file server need to turn on the boolean to expose the user's home directories.
The security policy of SE-PostgreSQL also provides a few booleans to allow end-users to customize its security policy. See the Pre-defined object types and booleans for more details.
security policy modules
The security policy to be loaded to the kernel consists of a base policy module and a few dozen of security policy modules. We can install, upgrade or uninstall security policy modules necessary or unnecessary.
The /usr/sbin/semodule is an interface to manage security policy modules. The -l option enables to display the list of installed security policy modules, the -i option enables to install a new security policy module, and so on.
[root@saba ~]# /usr/sbin/semodule -l amavis 1.7.0 amtu 1.1.0 apcupsd 1.3.0 : sepostgresql-devel 3.14 : xguest 1.0.0 zabbix 1.1.0
SE-PostgreSQL provides an additional security policy modules named as sepostgresql-devel.pp. It enables developers to control audit messages and to run the regression test correctly.
system-config-selinux
The system-config-selinux is a fine GUI utility to customize SELinux. It enables to set up the working mode of SELinux, the default security context of filesystem objects and network resources, the mapping between users and range on login time, human readable forms of ranges and policy modules.