Introduction To SELinux - The GitHub Blog
Introduction To SELinux - The GitHub Blog
Education Security
Introduction to SELinux
SELinux is the most popular Linux Security Module used to isolate and protect system components from one another. Learn about
different access control systems and Linux security as I introduce the foundations of a popular type system.
https://github.blog/2023-07-05-introduction-to-selinux/ 1/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Author
https://github.blog/2023-07-05-introduction-to-selinux/ 2/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
At GitHub Security Lab, our main mission is helping secure the open source We do newsletters, too
software we all rely on. While securing applications themselves is important,
Get tips, technical guides, and best
one of the best ways developers and system administrators can ensure the
practices right in your inbox.
security of their systems is to create multiple layers of privilege. Linux, the
most popular open source operating system, provides many security systems Subscribe
to do this, including allowing an administrator to give each service and user
the permissions it needs and preventing them from accessing resources they
don’t.
More on GitHub Security Lab
Today, I will be introducing SELinux, one of many security mechanisms that is
implemented into Linux. Despite many Linux distributions having Linux
Security Modules enabled by default, general knowledge of SELinux among
developers and system administrators is not as common as one would
expect. In addition, theoretical and practical knowledge about SELinux is
often dispersed across the internet, often written in blogs or forums from
years in the past. In this blog, I hope to introduce SELinux to developers and
GitHub and the Ekoparty 2023
administrators who are looking for a practical way to improve the security of
Capture the Flag
their systems that don’t have a security module enabled, and show those
The GitHub Security Lab teamed up
already running a module what SELinux has to offer. I will introduce the
with Ekoparty once again to create
differences between MAC and DAC, explain the basics of the SELinux type some challenges for its yearly Capture
system, suggest some useful tools and examples when interacting with the Flag competition!
SELinux, and give a succinct explanation of how SELinux works in the kernel. Logan MacLaren
which is a standard used to define permissions on systems. Access Control This blog post describes two linked
vulnerabilities found in Frigate, an AI-
can be divided into two main types: Discretionary access control (DAC) and
powered security camera manager,
Mandatory access control (MAC). Discretionary access control is based that could have enabled an attacker to
around owners, where an owner can decide who has access to its resources. silently gain remote code execution.
DACs are used in all modern day operating systems. For example, POSIX Logan MacLaren & Jorge Rosillo
operating systems assign an owner to each file/directory who can decide how
users in its group and outside its group can interact with the file. Another
example is Windows, NTFS permissions are slightly more complex allowing
Cueing up a calculator: an
introduction to exploit
for overlapping allow and deny permissions, but still follow an owner-centric development on Linux
model. MACs are much less popular and are based around the resources
Using CVE-2023-43641 as an
themselves, how sensitive they are and the level of access users need to example, I’ll explain how to develop an
access that level of sensitivity. MAC systems have become more popular in exploit for a memory corruption
the past years as the users are looking for better granularity and control over vulnerability on Linux. The exploit has
to bypass several mitigations to
the security of their system. Currently, some popular MAC systems include
achieve code execution.
seccomp, which is used by containerization software such as docker, and
Kevin Backhouse
Mandatory Integrity Control, which provides integrity levels to secure objects
on Windows. Today, we will look at one of the first MAC’s to be added to the
Linux kernel, SELinux.
Try Contact
/ Blog
SELinux
Engineering Product Security Open Source Enterprise
was originally a development project from the National Security
More GitHub
Copilot sales
https://github.blog/2023-07-05-introduction-to-selinux/ 4/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
frameworks exist, by far the two most popular are AppArmor, enabled by
default on recent Ubuntu versions, and SELinux, enabled by default on
Android 5.0+ and Red Hat/Fedora. In order to better understand SELinux
and how a security policy can be enforced, I will first introduce the basic
architecture of SELinux.
1. Firstly, a Subject must request access to take an action. In most cases, the
subject is a process that is requesting access to a resource. Access can
be controlled via Access Vector Rules, whose details will be presented
shortly.
2. Second, an Object Manager (OM) that controls the access of the subject.
It will query the Security Server in order to allow or deny actions.
https://github.blog/2023-07-05-introduction-to-selinux/ 5/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
source: https://github.com/SELinuxProject/selinux-notebook/raw/main/src/images/1-
core.png
There can only be one Security Server, which resides in the kernel. However,
the AVCs and OMs can reside both in the kernel and in userspace. In kernel
space, the Linux Security Modules framework is the OM, as it decides which
kernel services can be restricted by a security framework such as SELinux.
AVCs are normally implemented as a hashmap used to cache the decisions
in the kernel or userland implementations. In userspace, a single application
can be both the OM and the AVC for the resources it controls. This is possible
by utilizing the SELinux API in order to query the Security Server.
https://github.blog/2023-07-05-introduction-to-selinux/ 6/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
source: https://www.javacodemonk.com/explain-unix-file-permissions-cac6d25f
Here, rwx stands for read, write and execute respectively. Each box shows
the permissions for the owner, group member, and non-group member,
respectively. The owner of a file has the ability to change the permissions of
the files that they own. We can use the ls command with the lowercase L
flag in order to see the permissions of a Unix file.
policy> ls -l example
https://github.blog/2023-07-05-introduction-to-selinux/ 7/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
-rw-r--r-- 1 kevin staff 0 Apr 30 22:29 example
policy> ls -Z /etc/passwd
system_u:object_r:passwd_file_t:s0 /etc/passwd
where
User
The user represents a SELinux user. A SELinux user is separate from a Linux
user but can be assigned multiple Linux users and helps bridge the gap
between the Linux world and SELinux world. The names for SELinux users
will often end in _u .
Role
https://github.blog/2023-07-05-introduction-to-selinux/ 8/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
The role represents the role a user should be in. A role may have more than
one SELinux user and they end by convention in _r . Roles often represent
the job of a Linux user, such as an administrator, normal user, database
administrator, etc.
Type
Types are the most important part of a context as all rules are based on types,
and therefore the type of a subject, domain, or object decides its
permissions. When a type is associated with a process, it defines what
processes (or domains) the SELinux user (the subject) can access. When a
type is associated with an object, it defines what access permissions the
SELinux user has to that object. SELinux and type enforcement go hand in
hand. Users present in privileged SELinux domains generally labeled as
unconfined can often specify SELinux policy files, *.te files, in order to create
specific permissions for a type/domain. More information about this can be
found in the Security Policy section.
Range
https://github.blog/2023-07-05-introduction-to-selinux/ 9/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Please note that some Linux distributions have different MAC systems
enabled, and running multiple exclusive LSMs at the same time will cause
issues. For example, Ubuntu has AppArmor enabled by default, therefore
enabling SELinux while AppArmor is enabled will prevent you from booting
properly. Please check include/linux/lsm_hooks.h for the LSM_FLAG_EXCLUSIVE to
see if your LSM is exclusive.
We can run semanage login -l in order to get the mappings of the Linux user
to the SELinux user.
Here, we can see the root user is under the unconfined_u SELinux user. Here,
the __default__ means any user that is not explicitly defined in the
configuration file, so therefore any newly created Linux users are part of the
https://github.blog/2023-07-05-introduction-to-selinux/ 11/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
unconfined_u . For this example, I have manually mapped alice and bob Linux
users to the user_u SELinux user.
You can also look at the mappings without a tool by reading the
/etc/selinux/{SELINUXTYPE}/seusers file, but changes to this file will not apply
directly to the SELinux policy and will be overwritten.
In a similar fashion, the current range of sensitivities can be viewed using the
/etc/selinux/{SELINUXTYPE}/setrans.conf
Looking at the Fedora config, we see that only the s0 sensitivity is used in
Fedora across all subjects/objects and that Fedora supports categories from
0 – 1023.
Security policy
SELinux policy is a group of policy sources that define many of the
components we have been introduced to, such as the names, roles, types
etc. However, SELinux policies are usually not created from scratch. Instead,
you can use a baseline policy, called the reference policy, which provides
classes and rules that utilize the core Linux components. The reference
https://github.blog/2023-07-05-introduction-to-selinux/ 12/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
policy originated from the NSA, was maintained by Tresys and is now located
in the SELinuxProject github organization.
In addition to the reference policy, each individual vendor may edit the policy
in order to support their own services and improve security. In order to better
understand what a SELinux policy looks like, we will analyze the reference
policy to understand the basic structure of a policy and what can be
changed. In order to follow along, you can clone the repository located here:
https://github.com/SELinuxProject/refpolicy.
When opening a SELinux policy, a number of file types may appear and it is
useful to know their names and purpose. The most common file types you
will find are the .te and .if files, which make up the core of the SELinux
policy. .te files are the type enforcement files, and they make up the main
core of the logic behind the policies. In this file, you can write allow rules,
declare types or typedefs and call macros defined by .m4 files. While
browsing SELinux policies, you will encounter macros such as gen_context ,
whose name usually fully explains their purpose. These macros are defined
in .m4 files that are present in the policy. Next the .if are short for interface
files, which are macros but as their name suggests act as interfaces to the
domains introduced in the current module. Lastly, you will see file context
files, .fc , which specify a list of paths and contexts assigned to that path. In
the last section we used ls -Z to view the context of /etc/passwd, but we
can also see it defined in authlogin.fc:
https://github.blog/2023-07-05-introduction-to-selinux/ 13/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Upon opening the repository we can navigate to the policy folder where the
policies we are looking for. Here, we can see the flask , modules , and
support folders. Looking at the flask folder, whose name represents the first
SELinux iteration named Flux Advanced Security Kernel, we see a file called
initial_sids . Here, we can see the sids that are generated on boot in order to
properly identify a variety of different services. A SID is an int that is used to
identify a security context and used internally in the kernel as an identifier. In
order to see which SIDs correspond to which contexts, we can check out the
modules definitions and find an entry matching the format:
Here, we can see that objects created by the kernel, such as threads and
sockets, will be given the sid kernel, meaning their context. If we look at the
database in the security server, we can see the context structure holds some
of these initial sids, which includes their name, relevant information, context
and sid number. Generally, initial sids are not changed as they require
changes to the Linux kernel. In the Security Server’s sidtab, we can see how
the kernel may translate the sid to a context. In short, the context for non-
initial sids are located in the sidtab , which contains a tree of pointers called
roots. The Security Server uses the sid in order to obtain the correct level and
leaf node in sidtab->roots , then uses the sid in order to index into the pointer
https://github.blog/2023-07-05-introduction-to-selinux/ 14/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
to find the sidtab_entry with the correct context for the given sid. Similarly,
the isid member in sidtab contains an array of initial sids. Next, let’s look at
the acess_vectors file, where you see structures following the format:
class class_name
inherits common_name{
extra permission 1
…
}
Here, we can see the defined classes represent common objects in the
kernel, such as files, directories, sockets etc. If allowed by the config, types
can be given permissions to access classes of another type. Let’s take a
simple example,
This means that subjects of the type init_t are allowed to read files that
have the type user_home_t . This is called an allow rule, which is part of a
greater set of rules called access vector rules. The allow rule makes up the
majority and core of any SELinux policy, while dontaudit and auditallow
rules decide where auditing occurs, and lastly the neverallow rule nullifies
any previous and future allows.
https://github.blog/2023-07-05-introduction-to-selinux/ 15/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Looking into the modules folder, we can see that the policy is separated into
different categories, such as admin, apps, kernel, etc. These categories are
further divided into a module (which consists of .te (type enforcement), .fc
(interface file) and .if (file context) files), with each type enforcement file
starting with policy_module macro. Each module is compiled into a .pp file
which can be loaded into the operating system.
If you are interested in learning more about the SELinux internals, I would
recommend getting familiar with the contents of the modules folder for the
particular flavor of policy your software uses. It can help you understand the
definitions of many common macros and can be a good reference if you run
into any SELinux permission issues while interacting with the Linux system
and its native services.
https://github.blog/2023-07-05-introduction-to-selinux/ 16/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
This is an example of a AVC denial, with the relevant subject context, target
context, class, permissions and type. SELinux logs can be found under
/var/log/audit or /var/log/audit/audit.log or by using some helper binaries
such as sealert . Importantly, there is a tool called ausearch that allows you
to filter through this log by a variety of the fields I mentioned above. For
example, if I just want to see AVC (denials) then we can run ausearch -m AVC
After finding our denial, we first need to assess that the subject should be
able to access the target it’s been denied access to. We can write some rules
manually to bind these two together and solve the issue or we can use tools
such as use audit2allow , an application that takes in the denial log and
suggests new rules to add in order to fix our issue. In order to add our new
rules to the current SELinux policy, we can create a new module and install it
to the current system; policies are modular and can be updated on live
machines. First, create a .te file that contains all the new rules you would
like to apply to the policy. Ensure your type file has the policy_module(name,
version) macro in order to properly name your module, and ensure your file
names match your module name. Next, grab the Makefile from
/usr/share/selinux/devel/Makefile which we will use to compile files, and run
make module_name.pp
module_name.pp .
https://github.blog/2023-07-05-introduction-to-selinux/ 17/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Using the seinfo , we can view our newly created types and rules:
LSM Internals
In order to understand how SELinux can control services at the kernel level,
we must understand the Linux Security Module Framework, which is the
building block for many MAC systems. I will introduce some of the relevant
kernel structures of the LSM framework in order to better understand the
framework. First, we can see a list of LSM hooks present in the
security/security.c file, whose names represent the action and structure they
use to intercept. We can take the security_socket_create hook as an example:
Clicking on any one of these functions, we can see how LSM will hook the
service. In the case of security_socket_create :
https://github.blog/2023-07-05-introduction-to-selinux/ 18/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
int __sock_create(struct net *net, int family, int type, int protocol,
struct socket **res, int kern)
{
int err;
struct socket *sock;
const struct net_proto_family *pf;
/*
* Check protocol is in range
*/
if (family < 0 || family >= NPROTO)
return -EAFNOSUPPORT;
if (type < 0 || type >= SOCK_MAX)
return -EINVAL;
/* Compatibility.
https://github.blog/2023-07-05-introduction-to-selinux/ 19/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
actual LSM hooks, which use the call_hook function in order to access the
hook. LSM hooks must be initialized by the security module that wants to use
it or else they will return a default value. If we look into the SELinux module,
we can see each of the LSM_hooks being initialized by SELinux use the
LSM_HOOK_INIT macro
/*
* Initializing a security_hook_list structure takes
* up a lot of space in a source file. This macro takes
* care of the common case and reduces the amount of
* text involved.
*/
#define LSM_HOOK_INIT(HEAD, HOOK) \
{ .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } }
struct security_hook_heads {
#define LSM_HOOK(RET, DEFAULT, NAME, ...) struct hlist_head NAME;
#include "lsm_hook_defs.h"
#undef LSM_HOOK
} __randomize_layout;
https://github.blog/2023-07-05-introduction-to-selinux/ 20/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
function is the corresponding function for the socket_create LSM hook, and
therefore we can look at selinux_socket_create to see what it will do.
if (kern)
return 0;
return avc_has_perm(&selinux_state,
tsec->sid, newsid, secclass, SOCKET__CREATE, NULL);
}
Here, we can see the function will get the SELinux sid (newsid) for the
corresponding socket type and the sid (tsec->sid) for the current user, then
query the AVC (by calling avc_has_perm ) to see if this subject (process) can
create this new object (socket). While some objects may have a singular type,
SELinux may need to interact with a preexisting object whose type changes
based on user discretion. Here, LSM has introduced a *_security field into
many of the critical kernel objects, in the form of a void pointer to allow
https://github.blog/2023-07-05-introduction-to-selinux/ 21/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
modules to use them as they please. While sockets may not be an interesting
structure, files are structures whose type can change. Therefore, let’s see how
_security functions are used by SELinux. First, I will introduce selinux_inode ,
which returns the data stored at the inode struct using the i_security field.
dsec = inode_security(dir);
sbsec = selinux_superblock(dir->i_sb);
sid = tsec->sid;
https://github.blog/2023-07-05-introduction-to-selinux/ 22/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry;
rc = avc_has_perm(&selinux_state,
sid, dsec->sid, SECCLASS_DIR,
DIR__ADD_NAME | DIR__SEARCH,
&ad);
if (rc)
return rc;
rc = avc_has_perm(&selinux_state,
sid, newsid, tclass, FILE__CREATE, &ad);
if (rc)
return rc;
SELinux in practice
https://github.blog/2023-07-05-introduction-to-selinux/ 23/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
While understanding how SELinux works is great to know if you are interested
in OS internals, let’s take a look at how SELinux is implemented in
applications. First, we will take a look at a commonly used Linux password
tool, to get familiar with the API and understand how userspace programs
can query the kernel. After that, I will suggest an exercise for the reader to
better understand userland AVCs and Object Managers.
if (0 == is_selinux_enabled ()) {
return 0;
}
if (getprevcon_raw (&user_context_raw) != 0) {
fprintf (shadow_logfd,
_("%s: can not get previous SELinux process context: %s\n"),
https://github.blog/2023-07-05-introduction-to-selinux/ 24/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
shadow_progname, strerror (errno));
SYSLOG ((LOG_WARN,
"can not get previous SELinux process context: %s",
strerror (errno)));
return (security_getenforce () != 0);
}
Here, we can see that SELinux is checking if the current process context has
the permission passwd in the class passwd , which essentially allows a
process to change another user’s password. If we look at (via ls -Z )
/usr/bin/passwd , we see that it has the type passwd_t . When a user executes
/usr/bin/passwd , a domain transition occurs (if allowed by SELinux policy)
that allows the user to launch processes that run in other domains. In this
example, only the root user is checked for SELinux permissions. Thus, a
simple way to prevent the root user from running passwd to change
passwords would prevent this domain transition from occurring, and thus the
/usr/bin/passwd would run as another type without the correct permissions.
https://github.blog/2023-07-05-introduction-to-selinux/ 25/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
1. https://github.com/SELinuxProject/selinux-
notebook/blob/main/src/postgresql.md
2. https://wiki.postgresql.org/wiki/SEPostgreSQL_Introduction
Conclusion
In this blog, I introduced each of the core components of SELinux to help
new users understand the big picture. SELinux can secure and isolate
components in your system, and my goal is to help you decide if using
SELinux is right for you. I hope that in reviewing you now have a solid
understanding of SELinux policies and its implementation in both userland
and kernel space, and are able to find and understand simple SELinux logs.
The examples and resources provided in this blog post should help you get
started in exploring more about SELinux in your own system.
https://github.blog/2023-07-05-introduction-to-selinux/ 26/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Related posts
Security
https://github.blog/2023-07-05-introduction-to-selinux/ 27/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Build code security skills with the GitHub Secure Code Game
Learn to find and fix security issues while having fun with Secure Code Game, now with new challenges focusing on JavaScript,
Python, Go, and GitHub Actions!
Joseph Katsioloudes
Security
https://github.blog/2023-07-05-introduction-to-selinux/ 28/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
More developers will have to fix security issues in the age of shifting left. Here, we break down how SAST tools can help them find
and address vulnerabilities.
Nicole Choi
Security
https://github.blog/2023-07-05-introduction-to-selinux/ 29/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Eric Tooley
https://github.blog/2023-07-05-introduction-to-selinux/ 30/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Yes please, I’d like GitHub and affiliates to use my information for personalized communications, targeted advertising and campaign effectiveness. See the GitHub
Privacy Statement for more details.
https://github.blog/2023-07-05-introduction-to-selinux/ 31/32
2/19/24, 10:16 AM Introduction to SELinux - The GitHub Blog
Resources
https://github.blog/2023-07-05-introduction-to-selinux/ 32/32