Learn SELinux - Users, Roles & MLS/MCS
Episode 8 of 23

Learn SELinux - Users, Roles & MLS/MCS

Understanding the identity layer in SELinux: the difference between Linux users and SELinux users, login mapping with semanage login, the concept of roles to restrict administrator domain transitions, and the MLS and MCS mechanisms for hierarchical data classification and workload isolation.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In episode 7, you resolved denials with local policy modules. But there's one thing we haven't touched: who runs that process. So far we've talked about domains — but domains are entered by humans through login sessions. This episode 8 discusses the SELinux identity layer: users, roles, and two classification mechanisms, MLS and MCS.

This is also the episode where SELinux concepts start to feel "different" from regular Linux. If you're used to thinking in UIDs and groups, get ready: SELinux has its own list of users, completely separate from Linux accounts.

Linux Users and SELinux Users: Two Different Identities

Every process has two identities at once: a UNIX identity (UID, GID) governing traditional rights, and an SELinux security context. See your own login session's identity:

Check your own session context
id -Z

The output for a regular user on the targeted policy is usually unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023. The first part, unconfined_u, is the SELinux user — not the Linux account. A Linux user is mapped to one SELinux user, and this mapping determines the initial domain of all the processes they run.

Note

The analogy: a Linux account is the ID card at the building gate, while the SELinux user is the badge that determines which floors you're allowed to enter. Two different ID cards (alice and bob) can use the same badge — or different badges — depending on administrator policy.

The list of built-in SELinux users is shown with semanage user -l:

SELinux userInitial domainUsage
unconfined_uunconfined_tunrestricted, for admins and development
staff_ustaff_tadmin who can escalate to sysadm_t via role
user_uuser_tregular user with a locked domain
guest_uguest_thighly restricted guest user
xguest_uxguest_tguest user for desktop sessions
system_usystem domainfor daemons and system processes, not humans

Notice system_u: it's meant for system processes, not human logins. The default mapping used by all Linux users on the targeted policy is usually __default__ pointing to unconfined_u — this is why many admins feel "SELinux doesn't restrict anything" until they change this mapping.

Mapping Logins to SELinux Users

The mapping between Linux users and SELinux users is managed with semanage login:

View current login mappings
semanage login -l

Example output:

LinuxExample semanage login -l output
Login Name    SELinux User    MLS/MCS Range       Service
__default__   unconfined_u    s0-s15:c0.c1023     *
root          unconfined_u    s0-s15:c0.c1023     *
alice         user_u          s0                   *

To map a Linux account to a more locked-down SELinux user:

Map the alice account to user_u
sudo semanage login -a -s user_u alice

After this, all processes started by alice run in the user_t domain — far more tightly locked than unconfined_t. To apply it to all users except special ones, change __default__:

Change the default mapping
sudo semanage login -m -S targeted -s user_u __default__

The consequences are significant: if an application needs full freedom, it must be moved to a dedicated service account with a staff_u or similar mapping. This is the trade-off that always accompanies user access hardening.

Role: The Domain Transition Gate

A role is the set of domains an SELinux user is allowed to enter. A user's login session starts in the domain corresponding to their primary role, for example user_t. For admins, SELinux provides a controlled role transition: newrole moves the session to a higher role with re-authentication:

Escalate to the sysadmin role
newrole -r sysadm_r

This command requires your password again and puts your session in the sysadm_t domain — which has far greater administrative rights. Roles prevent silent escalation: even if a staff_u user is compromised, the attacker still has to go through newrole (with the victim's password) to gain admin rights.

The list of roles available to one SELinux user is managed with semanage user:

Give staff_u access to the sysadmin role
sudo semanage user -m -R "staff_r sysadm_r" staff_u

The right analogy: roles are the floors of a building, newrole is the elevator that requires the card again. The SELinux policy ensures processes can't just "ride the elevator up" without authorization.

MLS: Multi-Level Security

MLS (Multi-Level Security) implements the Bell-LaPadula model: every subject and object has a sensitivity level, from s0 (lowest) to s15 (highest). The basic rules are simple:

  • No read up — an s0 subject may not read s1 data.
  • No write down — an s1 subject may not write to an s0 object.

Look at the level range of each SELinux user in the earlier semanage user -l output: s0-s15:c0.c1023 means the whole sensitivity range from s0 to s15 is allowed. This range is the user's clearance. On an MLS policy, a user with s0 clearance will never read an s1 document, even if type rules allow it.

MLS systems are rarely used outside government and military environments — that's where terms like top secret and secret become real levels in the policy. For most companies, the more relevant mechanism is MCS.

MCS: Multi-Category Security

MCS (Multi-Category Security) shares the same infrastructure as MLS but uses categories instead of hierarchy. Categories are numbered c0 through c1023, and levels are written like this:

  • s0:c0.c1023 — all categories from c0 to c1023.
  • s0:c1,c3 — only categories c1 and c3.

Unlike MLS, which is hierarchical, MCS categories are not graded: c2 isn't "higher" than c1. They're just group labels for lateral isolation — separating one workload from another even though both run on the same host.

Categories are what let container runtimes separate processes: each container gets a unique category, for example s0:c123, so container A's processes can't read container B's files just because both share the same type. Set a directory's category range with chcon:

Label a directory with a specific category
sudo chcon -r s0:c1 /srv/tenant-a

Tip

A way to remember the difference: MLS is a height hierarchy (can be read upward or downward), MCS is a separation between rooms (not interconnected). MLS is for high-assurance systems with hierarchical clearance, MCS for isolation between tenants and workloads — a pattern we'll see again in the container episode.

Closing

In this episode 8, you've understood that SELinux identity is layered in three parts: the SELinux user determines identity and level range, roles restrict which domains can be entered, and the MLS/MCS level determines what data can be read. You've also mapped Linux accounts to SELinux users with semanage login and raised privileges in a controlled way with newrole.

The key takeaways:

  • Linux users and SELinux users are two different things, connected by semanage login.
  • Roles + newrole prevent unauthenticated privilege escalation.
  • MLS for hierarchical classification, MCS for isolation between workloads.

Now that identity is in order, it's time to use it on the most popular services in the world. In episode 9, we'll apply all these concepts to Web Server & Application Services: the correct file contexts for Nginx and Apache, booleans for network and database connections, port labeling with semanage port, and multi-instance patterns for MySQL and PostgreSQL.