SELinux basics

I recently came in touch with SELinux when I had to write/extend a policy for a commercial app. This post is some kind of notepad/cheatsheet I created while learning the topic. The aim is to document the concepts and commands which are necessary in order to be able to understand the basics and modify/adjust an existing SELinux policy.

What is SELinux

SELinux is an implementation of a mandatory access control mechanism (MAC) in the Linux kernel. It enforces rules on files and processes in a Linux system, and on their actions, based on defined policies.

It checks for allowed operations after standard discretionary access control mechanism (DAC = the traditional Unix permissions) is checked.

Linux processes are referred to as subjects. Files, including directories and devices, are referred to as objects.

Basic Concepts

Security Context

A security context, or security label, is the mechanism used to classify resources, such as processes and files.

Processes and files are labeled with an SELinux security context that contains information, such as an SELinux user, role, type, and optionally, a level. When running SELinux, all of this information is used to make access control decisions.

The security context is usually written in the format:


As a naming conventions the following suffixes are used: _u for user, _r for role, _t for type (or domain when it is for a running process).

All processes and files have a SELinux security context.

Security Context of Processes

The security context of processes can be shown with ps -Z, e.g.:

> ps -ZC httpd
LABEL                             PID TTY          TIME CMD
system_u:system_r:httpd_t:s0     3826 ?        00:00:00 httpd

where the LABEL system_u:system_r:httpd_t:s0 is the security context.

Security Context of Files and Directories

The security context of a file or directory is stored as extended file attribute. It can be shown with ps -Z, e.g.:

> ls -Z /var/www/
drwxr-xr-x. root root system_u:object_r:httpd_sys_script_exec_t:s0 cgi-bin
drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 html

or with stat, e.g.:

> stat -c %C /var/www/html/

where the part system_u:object_r:httpd_sys_content_t:s0 is the security context.


A subject is an active process with a security context associated with it.


An object is a resource such as files, sockets, pipes or network interfaces that are accessed by processes (subjects)


A domain is part of the security context of a subject (process):



A type is part of the security context of an object (file):



A Policy specifies granted permissions in an SE-Linux system.

It basically defines:

  1. types for file objects and domains for processes
  2. rules on security contexts (see above), specifying which domains are allowed to access which types.

On an SELinux system, everything is denied by default, only what is specifically allowed by a rules is permitted. An SELinux policy is a set of rules specifying what is allowed on a system.

Linux distributions with SELinux support usually ship with a default policy containing hundreds or even thousands of rules.

On Red Hat/CentOS the default policy is the “targeted” policy. When using targeted policy, processes that are targeted run in a confined domain, and processes that are not targeted run in an unconfined domain.

Enabling/disabling SELinux

SELinux can run in three different modes:

  • enforcing: SELinux policy is enforced. SELinux denies access based on SELinux policy rules.
  • permissive: SELinux does not deny access, but denials are logged for actions that would have been denied if running in enforcing mode.
  • disabled: SELinux disabled

Current status can be checked with getenforce or sestatus. The mode is configured in the default SELinux config file /etc/selinux/config:


A system reboot is required for changes to take effect. To switch between enforcing and permissive setenforce [0|1] can be used.

SELinux type enforcement

In SELinux, all subjects and objects have a type identifier associated to them – the type identifier is the _t part of the security context (see above).

Type enforcement is the feature of SELinux that uses that type to enforce rules laid down by policy.

A type enforcement rule has the following structure:

allow <domain> <type>:<class> { <permissions> };
  • <domain> is the context of a process
  • <type> is the context of the resource on which the process is acting
  • <class> is the kind of the resource
  • <permissions> are the permissions of the <domain> on the <type> of <class>


allow innd_t usr_t:file { getattr read ioctl }

Reads as: allow processes running in the innd_t domain to do getattr, read and ioctl on files of type usr_t.

Querying SELinux rules

To query SELinux if a certain rule is active, sesearch can be used. E.g., to search rules allowing file write access from processes of domain httpd_t:

> sesearch --allow --source httpd_t --target httpd_sys_content_t --class file --perm write
Found 1 semantic av rules:
   allow httpd_t httpdcontent : file { ioctl read write create getattr setattr lock append unlink link rename open } ;

Controlling file contexts

Listing file contexts mappings

To list all default file context mapping definition, specified in the current policy:

> semanage fcontext -l
/.*                                                all files          system_u:object_r:default_t:s0
/etc/.*                                            all files          system_u:object_r:etc_t:s0 
/lib/.*                                            all files          system_u:object_r:lib_t:s0 
/usr/.*\.cgi                                       regular file       system_u:object_r:httpd_sys_script_exec_t:s0 
/opt/.*\.cgi                                       regular file       system_u:object_r:httpd_sys_script_exec_t:s0 
/root(/.*)?                                        all files          system_u:object_r:admin_home_t:s0 
/dev/[0-9].*                                       character device   system_u:object_r:usb_device_t:s0 

Note that semanage fcontext -l does not show the “auto-generated” contexts, such as with home directory contexts.

To get the default SELinux security context for the specified path from the file contexts configuration, matchpathcon can be used:

> matchpathcon /etc/
/etc	system_u:object_r:etc_t:s0

Note that the default context is not necessarily the currently applied context. So the context shown by matchpathcon FILE and ls -Z FILE don’t have to be the same. This is the case when changing a file context mapping definition but it’s not yet applied with restorecon.

Changing file contexts (labeling files)

Making temporary changes

To temporally label a FILE the with type var_log_t, use chcon:

chcon -t var_log_t FILE

ls -Z will immediately reflect the canges. But the changes are not stored in the policy, only the file labels are changed. So matchpathcon FILE will show the same labels as before chcon.

A system reboot or calling restorecon will “revert” the changes by apply the default policy again.

Making persistent changes

  1. Change context mapping with, semanage fcontext, e.g. to label files in /srv/logs/ with type var_log_t:

    semanage fcontext -a -t var_log_t "/srv/logs(/.*)?" 

    The new context mapping is stored persisently in the policy, e.g. when using the targeted policy, files are written to /etc/selinux/targeted/contexts/files/

  2. to actually apply the mapping to the files, run restorecon:

    restorecon -Rv /srv/logs

Searching file contexts

findcon searches for files/mappings with a specified context.

If the first parameter is a file context file, findcon prints matching entries, e.g. find mappings applying to /var/cache:

> findcon /etc/selinux/targeted/contexts/files/file_contexts -p /var/cache/
/.*	  	system_u:object_r:default_t:s0
/var/.*	  	system_u:object_r:var_t:s0

If the first parameter is a file or directory, mathing files are printed, e.g. find files/directories with type var_t:

> findcon /var/cache -t var_t
/var/cache	-d	system_u:object_r:var_t:s0
/var/cache/powertop/saved_results.powertop	--	system_u:object_r:var_t:s0

Deleting context definitions

File context definitions mapping label var_log_t to /srv/logs(/.*)? can be removed with:

semanage fcontext -d -t var_log_t "/srv/logs(/.*)?"

to actually apply the changes, run restorecon:

restorecon -Rv /srv/logs

Controlling process contexts

Querying policies

The SELinux policy query tool sesearch can be used to search for rules in a policy, e.g. to search for rules allowing file write access from domain auditd_t to files with type label auditd_log_t:

> sesearch --allow --source auditd_t --target auditd_log_t --class file --perm write
Found 1 semantic av rules:
   allow auditd_t auditd_log_t : file { ioctl read write create getattr setattr lock append unlink link rename open } ;

SELinux permission denial details

One of the most important features of SELinux is, that it is able to log everything! And with everything, I mean everything. If we want, we can have SELinux even log all granted accesses, but more importantly it logs access denials.

The default location of the audit log depends on the distribution, but usually it is one of the following /var/log/audit/audit.log, /var/log/audit.log or /var/log/avc (if you are not running the audit daemon auditd).

If SELinux denies access, a log entry with type=AVC (Access Vector Cache) is written. This is an example from my audit.log:

type=AVC msg=audit(1483812519.383:165): avc:  denied  { create } for  pid=3057 comm="gdm-session-wor" name="gdm" scontext=system_u:system_r:xdm_t:s0-s0:c0.c1023 tcontext=system_u:object_r:admin_home_t:s0 tclass=dir

Means that the gdm proccess with pid=3057 with domain context system_u:system_r:xdm_t:s0-s0:c0.c1023 was denied to create a dir in a file system context tcontext=system_u:object_r:admin_home_t:s0

The timestamp 1483812519.383 is in seconds since epoch January 1st, 1970. It can be converted to a more human readable format using date -d @1483812519.383 => Sat Jan 7 19:08:39 CET 2017

There is also the ausearch command. It is a Linux audit related utility (not SELinux specific), which parses the audit logs and allows to query the entries in the logs. One of the advantages that it shows is that it already converts the time stamp into a human readable one:

> ausearch -m avc --start recent
time->Sat Jan  7 13:08:39 2017
type=AVC msg=audit(1483812519.383:165): avc:  denied  { create } for  pid=3057 comm="gdm-session-wor" name="gdm" scontext=system_u:system_r:xdm_t:s0-s0:c0.c1023 tcontext=system_u:object_r:admin_home_t:s0 tclass=dir


ps -Z                       # show security context of processes
ls -Z [FILE]                # show security context of file(s)
stat -c %C FILE             # show security context of file
chcon                       # change file security context (temporally)
semanage ...                # the SE-linux policy management tool
semanage fcontext -a        # add file file context rule
semanage fcontext -d        # delete file context rule
semodule                    # the selinux policy modules management tool
semodule -l                 # list installed modules 
semodule -i                 # install module
restorecon                  # restore file(s) default SELinux security contexts
audit2allow                 # generate SELinux policy allow/dontaudit rules from logs of denied operations
audit2why                   # translates SELinux audit messages into a description of why the access was denied
findcon                     # file context search tool
findcon DIR -t TYPE         # searches for files/dirs beyond DIR labeled with TYPE
sesearch                    # SELinux policy query tool
ausearch -m avc --start [recent|today|...]   # query audit daemon logs


Very good resources on the topic:

comments powered by Disqus