SELinux Deep Dive: Mandatory Access Control Mastery Projects

Goal: Build a deep, practical mental model of SELinux as a Mandatory Access Control (MAC) system: how the Linux Security Modules (LSM) framework routes security decisions, how labels and types are the core currency of policy, and how to write, test, and deploy policy modules without disabling protection. By the end, you will confidently troubleshoot AVC denials, design least-privilege policies for real applications, and operate SELinux across hosts, containers, and compliance-driven environments. You will move from “setenforce 0” to “policy-driven reliability” with evidence-backed fixes.


Introduction

SELinux (Security-Enhanced Linux) is a kernel-level MAC system that enforces access decisions based on labels and policy rules, not just Unix users and groups. It answers a deeper security question: “Is this process type allowed to perform this action on that object type under this policy?” The result is least-privilege enforcement that continues to work even if a process is compromised.

What you will build (by the end of this guide):

  • A complete SELinux investigation toolkit (context viewer, AVC analyzer, policy diffing)
  • Custom policy modules and automated labeling workflows for real services
  • Container isolation labs using SELinux labels and MCS categories
  • An enterprise-scale SELinux monitoring and remediation platform

Scope (what’s included):

  • SELinux architecture, labeling, type enforcement, domain transitions
  • Policy tooling (audit2allow, semanage, semodule, sepolicy, checkmodule)
  • Troubleshooting workflow (AVC, audit logs, sealert)
  • Containers and MLS/MCS classification

Out of scope (for this guide):

  • Full Linux kernel LSM development from scratch
  • Writing an entire SELinux policy distribution
  • Deep OS hardening beyond SELinux (AppArmor, grsecurity, etc.)

The Big Picture (Mental Model)

Userspace                          Kernel
┌─────────────────────┐           ┌─────────────────────────────────────┐
│  process (httpd_t)  │           │  Linux Security Modules (LSM)       │
│  file (/var/www)    │           │  ┌───────────────┐                  │
│  socket (:80)       │  syscalls │  │ SELinux hooks │ -> allow/deny     │
│  policy tools       │ ─────────►│  └──────┬────────┘                  │
└─────────────────────┘           │         │                           │
                                  │   ┌─────▼─────┐                    │
                                  │   │ Security  │                    │
                                  │   │ Server    │                    │
                                  │   └─────┬─────┘                    │
                                  │         │                           │
                                  │   ┌─────▼─────┐                    │
                                  │   │ AVC Cache │                    │
                                  │   └───────────┘                    │
                                  └─────────────────────────────────────┘

Key loop: syscall -> LSM hook -> policy lookup -> allow/deny -> audit log

Key Terms You’ll See Everywhere

  • Context: The SELinux label in the form user:role:type:level.
  • Type: The primary component used in Type Enforcement (TE) decisions.
  • Domain: A process type (e.g., httpd_t).
  • AVC: Access Vector Cache; stores recent decisions for speed.
  • Policy: The rules that decide which type can do what.
  • Boolean: A runtime switch that toggles parts of policy.

How to Use This Guide

  • Read the primer first: The Theory Primer is your mini-book; it prevents random trial-and-error debugging.
  • Build in evidence loops: Each project asks you to capture logs, contexts, and policy decisions.
  • Stay in enforcing mode: Learn to fix denials, not disable security.
  • Record decisions: Keep a short lab notebook with denials, fixes, and the policy change that resolved them.
  • Iterate in layers: First get it working; then tighten policy and document trade-offs.

Prerequisites & Background Knowledge

Before starting these projects, you should have foundational understanding in these areas:

Essential Prerequisites (Must Have)

Linux Fundamentals:

  • Comfortable with basic shell usage, permissions, and file ownership
  • Familiarity with systemd services and logs (journalctl)

C or Systems Programming Basics:

  • Understand processes vs threads, system calls, and basic Linux I/O

Security Basics:

  • Know the difference between authentication and authorization
  • Understand DAC (owner/group/other) and why it fails under compromise

Helpful But Not Required

Containers / Virtualization:

  • Helpful for Project 5 and Project 10

Ansible / Automation:

  • Helpful for Project 9 and the Final project

Kernel Debugging / Tracing:

  • Helpful for Project 11

Self-Assessment Questions

  1. Can you read a file’s permissions and explain who can access it?
  2. Can you use ps, ls, and journalctl to inspect a process and its logs?
  3. Do you know what a system call is and why it matters for security?
  4. Can you explain the difference between a user ID and a process label?
  5. Can you copy a file and explain how its metadata might change?

If you answered “no” to questions 1-3, spend a week on Linux basics first.

Development Environment Setup

Required Tools:

  • Linux VM (Fedora, RHEL, AlmaLinux, Rocky, or Debian + SELinux)
  • policycoreutils, selinux-policy, setroubleshoot, audit
  • semanage, audit2allow, audit2why, seinfo, sesearch

Recommended Tools:

  • strace, ausearch, aureport
  • podman or docker for container projects
  • ansible for automation projects

Testing Your Setup:

$ sestatus
$ getenforce
$ ls -Z /
$ ps -eZ | head
$ ausearch -m avc -ts recent

Time Investment

  • Small projects (1, 4, 6, 7): 4-8 hours each
  • Medium projects (2, 3, 8, 9): 1-2 weeks each
  • Large projects (5, 10, 11, Final): 2-8 weeks each

Important Reality Check

SELinux mastery is a long game. Expect to iterate:

  1. First pass: get the system working (permissive for analysis is OK)
  2. Second pass: read denials and fix labeling and booleans
  3. Third pass: write policy and validate least privilege
  4. Fourth pass: automate and document

Big Picture / Mental Model

Access Decision Pipeline

process (type) + target (type) + class + permission
               │
               ▼
        AVC cache lookup
        │        │
     hit        miss
      │          │
      ▼          ▼
  allow/deny   security server -> policy rules
      │          │
      └──────────┘
               │
               ▼
           audit log

Theory Primer

Concept 1: SELinux Architecture and the LSM Enforcement Pipeline

Fundamentals

SELinux is not an application or a daemon; it is a kernel-enforced Mandatory Access Control system integrated through the Linux Security Modules (LSM) framework. LSM provides the hook points where the kernel asks a security module to approve or deny an action. SELinux implements a policy engine (security server) and an Access Vector Cache (AVC) that stores recently evaluated decisions. When a process tries to open a file, bind a port, or transition to a new domain, the kernel calls an LSM hook, which consults SELinux policy. If the decision is denied, the action is blocked and logged. This pipeline makes SELinux consistent, auditable, and enforceable in ways that user-space tools cannot match. The key mental model is that SELinux lives between system calls and kernel objects, and every decision is based on labels and policy rules.

Deep Dive

The Linux Security Modules framework is a kernel architecture that provides hooks for access control decisions. It is not itself a policy; it is infrastructure. The kernel uses LSM hooks at critical points such as file access, process creation, socket operations, and IPC. When these hooks are invoked, SELinux consults its security server, which evaluates the loaded policy against the subject and object contexts. The subject is usually a process type (domain), and the object is a file, socket, port, or another process. The kernel supplies the object class (e.g., file, dir, tcp_socket) and requested permissions (e.g., read, write, connect). The security server does a policy lookup, and the result is cached in the AVC to avoid repeated computation. This caching is essential for performance; without it, even file-heavy workloads would slow significantly. However, the cache introduces a nuance: if policy changes, the cache must be invalidated so old decisions do not linger.

LSM modules are not loadable in the traditional sense; they are selected at kernel build time and can be ordered or overridden at boot via kernel parameters (e.g., security=). The active LSM list is exposed at /sys/kernel/security/lsm, which shows the evaluation order. This matters because SELinux is typically the "major" module and follows the capability checks, so access decisions are layered rather than replacing DAC.

SELinux policy is compiled and loaded into the kernel. This means policy evaluation happens in kernel context, which is more reliable than user-space enforcement. Policies can be modular, and changes can be loaded without rebooting. This is critical for real-world operations. When you change a boolean or load a new module, SELinux updates its policy store and invalidates relevant cache entries. The audit subsystem is tied into SELinux so that denied access attempts are logged in a structured format, creating a feedback loop for troubleshooting.

This architecture is a layered system. At the top, you have your applications. At the kernel boundary, system calls attempt actions. LSM hooks capture those actions, and SELinux checks whether the requested operation is allowed for the process type to interact with the object type. If denied, the kernel returns EACCES or EPERM, and an AVC message is logged. This is why SELinux can be invisible unless you check logs: it surfaces as a normal permission error. The difference is that the root cause is not Unix permissions; it is the SELinux policy decision.

Key invariants: every access decision is deterministic given the current policy, the subject context, the object context, the class, and the permission. This is why troubleshooting is systematic: you can reproduce decisions by recreating context, or by reviewing sesearch results. Another important invariant is that SELinux labels are carried by kernel objects. A file’s label is stored in extended attributes, a process label is maintained in task_struct. This ensures that decisions remain bound to the object, even if the object is moved or accessed by multiple users.

This concept anchors all projects. You are not building “SELinux scripts”; you are interacting with a policy engine embedded in the kernel. Every project you build is a microscope pointed at this pipeline: Project 1 visualizes contexts, Project 2 parses AVC denials, Project 11 watches LSM hooks fire. The key to mastery is understanding how a high-level action (like curl http://localhost) turns into multiple LSM checks and AVC decisions. Once you see that, SELinux stops being mystical and becomes observable infrastructure.

How This Fits on Projects

Understanding the enforcement pipeline is required for Projects 1, 2, 8, and 11 because these projects directly analyze the decision path and logs.

Definitions & Key Terms

  • LSM hook: Kernel entry point for security decisions.
  • AVC: Cache of allow/deny decisions.
  • Security server: SELinux policy engine in the kernel.
  • Policy store: Compiled policy loaded into kernel memory.

Mental Model Diagram

Syscall -> LSM hook -> AVC check -> policy lookup -> allow/deny -> audit

How It Works (Step-by-Step)

  1. A process makes a system call (e.g., open).
  2. The kernel invokes the relevant LSM hook.
  3. SELinux checks the AVC for a cached decision.
  4. If cache miss, the security server evaluates policy rules.
  5. Decision is returned and cached.
  6. Denials are logged to audit.

Minimal Concrete Example

# Show active LSMs (order matters)
$ cat /sys/kernel/security/lsm
capability,selinux

Common Misconceptions

  • “SELinux is a daemon you can stop.” -> It is a kernel module; stopping a daemon does not disable it.
  • “SELinux only applies to files.” -> It applies to many object classes: sockets, ports, IPC, processes.

Check-Your-Understanding Questions

  1. Where does SELinux make the allow/deny decision?
  2. Why is the AVC necessary?
  3. What data must be known to evaluate a decision?

Check-Your-Understanding Answers

  1. Inside the kernel through LSM hooks.
  2. To avoid repeated policy evaluation overhead.
  3. Subject context, object context, class, permission, and policy.

Real-World Applications

  • Preventing a compromised web server from reading /etc/shadow.
  • Blocking container escapes by restricting access to host-labeled files.

Where You’ll Apply It

  • Projects 1, 2, 8, 11, Final

References

  • Linux Kernel LSM documentation (docs.kernel.org)
  • Android SELinux overview (AOSP)

Key Insights

SELinux is not a tool you run; it is a kernel pipeline you observe and influence through labels and policy.

Summary

SELinux integrates with the kernel via LSM hooks, evaluates policy in-kernel, caches decisions, and logs denials. This architecture makes SELinux reliable and auditable.

Homework/Exercises

  1. List active LSMs and explain the order.
  2. Trigger a denial by trying to read a protected file from a confined domain.

Solutions to Homework/Exercises

  1. cat /sys/kernel/security/lsm shows the list and order.
  2. Run httpd in enforcing mode and try to read a file labeled shadow_t.

Concept 2: Security Contexts and Labeling

Fundamentals

Every SELinux decision is anchored to a security context: user:role:type:level. These labels are attached to processes, files, ports, and other kernel objects. The type is the most important element for type enforcement, but the other components matter for role-based access control (RBAC) and multi-level security (MLS/MCS). Labels are stored with files in extended attributes and are part of process metadata in the kernel. This means that copying, moving, or relabeling files can directly change which process can access them. Most SELinux problems in real systems are labeling problems: files end up with the wrong type. Tools like restorecon, semanage fcontext, and chcon exist to manage these labels. If you can read and reason about contexts, you can diagnose 80% of SELinux issues quickly.

Deep Dive

The security context is the identity of an object in SELinux. The common format is SELinux user:role:type:level. The SELinux user is mapped from the Linux user and influences which roles are available. The role constrains which process types a user can enter. The type is used by Type Enforcement to decide access between processes and objects. The level represents MLS/MCS sensitivity and categories, which control access based on classification rules. In targeted policies, the level is usually s0, but in MLS or MCS configurations, categories (like s0:c123,c456) are used to isolate tenants, containers, or virtual machines.

File contexts are stored in extended attributes (security.selinux). That means the label travels with the file, not with the path. However, policy defines default file context patterns based on paths. Tools like restorecon read the policy file context database and apply default labels to files, while semanage fcontext allows you to create persistent overrides. If you change a file path (move it into /srv/myapp), SELinux does not automatically update labels. That is why a service works in /var/www but fails in /opt/app - the file contexts differ. The fix is usually: define a file context rule and relabel with restorecon.

The label assigned to a new file is usually inherited from the parent directory, but the final label is chosen by the most specific file-context rule that matches the path. That means directory layout matters. If you move a directory tree across mount points or unpack tar archives, you can easily end up with an inconsistent labeling state. Utilities like matchpathcon and semanage fcontext -l let you compare the actual label to the policy’s expected label. This comparison is the backbone of automated drift detection and is the reason Project 6 can be fully automated.

Processes get their contexts from the executable they run and the domain transition rules. This means the label of a binary (httpd_exec_t) influences the label of the process (httpd_t) after execution. If you relabel a binary incorrectly, you might break its transitions. Similarly, ports and network resources can have labels; SELinux can decide whether a process type is allowed to bind to a port type. That is why semanage port exists.

Labeling is a lifecycle. Files are created with labels based on parent directories, file context patterns, and the creating process. If you mount a filesystem without SELinux support or with incorrect mount options, labels can be lost or assigned the generic default_t. That can cause widespread denials. To fix this, you may need to relabel the filesystem or use setfiles on boot. Copying files is another source of label drift. Some copy tools preserve context (cp -a), others do not. This matters when you deploy configuration files for services; wrong labels often cause silent failures.

The important operational habit is to never use chcon as a permanent fix. chcon is useful for experimentation, but policy updates or relabel operations can revert it. Use semanage fcontext to make a permanent mapping, then run restorecon. Your projects will repeatedly practice this workflow. Project 1 visualizes contexts across processes and files. Project 6 checks for context drift. Project 7 audits port labels. Project 9 enforces consistent labels across a fleet.

How This Fits on Projects

Projects 1, 6, 7, 9, and 10 require accurate context interpretation and relabeling workflows.

Definitions & Key Terms

  • Context: user:role:type:level label assigned to an object.
  • File context: Default label mapping based on path regex.
  • restorecon: Reapply default labels from policy.
  • semanage fcontext: Persistently define label rules.

Mental Model Diagram

Path -> file context pattern -> label stored in xattr
Process exec -> binary label -> domain transition -> process label

How It Works (Step-by-Step)

  1. A file is created under a labeled directory.
  2. The kernel assigns a label based on file context rules.
  3. A process executes a binary; the binary label drives domain transition.
  4. Access decisions are made based on source/target labels.

Minimal Concrete Example

# View file and process labels
$ ls -Z /var/www/html/index.html
$ ps -eZ | grep httpd

# Create a persistent file context
$ semanage fcontext -a -t httpd_sys_content_t "/srv/myapp(/.*)?"
$ restorecon -Rv /srv/myapp

Common Misconceptions

  • “Permissions are correct so SELinux won’t block it.” -> SELinux can still deny.
  • “chcon is permanent.” -> It is not; restorecon can revert it.

Check-Your-Understanding Questions

  1. Where is a file’s SELinux label stored?
  2. Why does moving a file break SELinux access?
  3. What’s the permanent way to change a label?

Check-Your-Understanding Answers

  1. In extended attributes (xattr), e.g., security.selinux.
  2. The path-based default label mapping no longer applies.
  3. semanage fcontext + restorecon.

Real-World Applications

  • Relabeling a custom web root for Apache.
  • Auditing container volumes for correct labels.

Where You’ll Apply It

  • Projects 1, 6, 7, 9, 10

References

  • Oracle Linux SELinux context documentation
  • Red Hat SELinux user guide

Key Insights

Labels are the primary identity in SELinux; get labeling right and most denials disappear.

Summary

Security contexts identify subjects and objects. Understanding labeling, file context rules, and relabeling tools is essential for stable SELinux behavior.

Homework/Exercises

  1. Change a file path and observe label drift.
  2. Use semanage fcontext to persist the correct label.

Solutions to Homework/Exercises

  1. Move a file from /var/www to /srv/www and check ls -Z.
  2. Apply semanage fcontext and run restorecon.

Concept 3: Type Enforcement and Policy Language

Fundamentals

Type Enforcement (TE) is the heart of SELinux. It defines what a process type can do to an object type. TE rules are written in policy files as allow statements that specify source type, target type, object class, and permissions. For example, allow httpd_t httpd_sys_content_t:file { read open }; means the httpd_t process can read files labeled httpd_sys_content_t. This model applies least privilege by default: if there is no rule, access is denied. TE scales because types group access patterns, and attributes can group related types. Policy is compiled and loaded into the kernel, which enforces it. Understanding TE is required for writing or debugging any custom policy.

Deep Dive

The SELinux policy language is a domain-specific language describing access control. It is compiled to a binary policy that the kernel can evaluate quickly. TE rules are the most common. Each rule has a source type (usually a process domain), a target type (file or object), an object class (file, dir, socket, etc.), and a set of permissions. This makes policy explicit and auditable. You can also define attributes to group types, which lets you apply rules to multiple types at once. For example, you might define a web_server_type attribute that includes httpd_t and nginx_t and then grant access to shared resources.

Beyond allow, policy includes dontaudit to suppress expected denials and neverallow to enforce invariants (policy sanity constraints). neverallow is powerful: it prevents accidental creation of rules that violate security boundaries. It is common in base policy to ensure untrusted domains never access certain types. Misunderstanding dontaudit is a common pitfall; it can hide real issues. Use dontaudit only after verifying the behavior is correct and expected.

Policy also defines types, roles, and users. Types are usually created with macros or policy modules, but you can declare new types in custom modules. Each type must be referenced in require blocks unless defined in the module itself. Policy modules are compiled and loaded into the kernel. The kernel does not care about source .te files; it only uses the compiled .pp or policy store. This means troubleshooting requires you to reason about the compiled policy, not the source. Tools like sesearch and seinfo help query the policy store, showing you whether a rule exists.

Modern SELinux policies are built from interfaces and macros defined in the reference policy. These interfaces provide higher-level abstractions like files_read_etc_files() or logging_log_file(), which expand into multiple allow rules. Using interfaces makes policies more consistent and less error-prone. It also makes diffing changes easier: you can track which interfaces were added rather than raw allow rules. When you write custom policy, consider using existing interfaces first. If no interface exists, you can define your own in the .if file and consume it in the .te file. This modular structure is a big part of why SELinux policies remain maintainable at scale.

Object classes have defined permissions. For example, file permissions include read, write, open, getattr, while socket permissions include connect or bind. This is why AVC messages include class and permissions: they tell you which rule is missing. When debugging, map the denial to a rule: source type, target type, class, permission. Then decide whether to add an allow, label differently, or change configuration.

Another subtlety: policy is hierarchical. The base policy includes default rules for system services. Custom modules add more. When you use audit2allow, it generates raw allow rules from denial logs. This can be dangerous because it may allow more than intended. The right approach is to interpret the denial, adjust labeling or booleans first, and only then create a policy module that grants the exact required access. Your projects will practice this: Project 2 interprets AVC denials, Project 3 writes custom rules, Project 8 compares policy changes, and the Final project automates safe policy management.

How This Fits on Projects

Projects 2, 3, 8, 11, and the Final project require TE literacy.

Definitions & Key Terms

  • allow rule: Grants permission for source to target.
  • neverallow: Policy constraint that forbids rules.
  • dontaudit: Suppresses noisy denials.
  • attribute: Groups types to simplify policy.

Mental Model Diagram

source_type  ->  target_type : class { permissions }
httpd_t      ->  httpd_sys_content_t : file { read open getattr }

How It Works (Step-by-Step)

  1. Policy defines types and attributes.
  2. Rules map allowed interactions.
  3. The kernel checks rules at runtime.
  4. Absence of rule = denial.

Minimal Concrete Example

# local_httpd.te
policy_module(local_httpd, 1.0)

require {
    type httpd_t;
    type httpd_sys_content_t;
    class file { read open getattr };
}

allow httpd_t httpd_sys_content_t:file { read open getattr };

Common Misconceptions

  • “audit2allow fixes everything” -> It might over-permit. Use carefully.
  • “SELinux rules work like ACLs” -> SELinux rules are separate from DAC.

Check-Your-Understanding Questions

  1. What is the structure of an allow rule?
  2. Why are neverallow rules useful?
  3. When should you use dontaudit?

Check-Your-Understanding Answers

  1. source type, target type, class, permissions.
  2. They enforce invariants and prevent unsafe policy changes.
  3. Only when denials are expected and harmless.

Real-World Applications

  • Granting a custom daemon access to a log directory.
  • Tightening a policy to block unexpected connections.

Where You’ll Apply It

  • Projects 2, 3, 8, 11, Final

References

  • SELinux policy reference (SELinux Notebook)
  • Red Hat SELinux guides

Key Insights

Type Enforcement is a precise language of least privilege: if you can read AVCs, you can write rules.

Summary

TE rules define what is allowed. The kernel enforces them on every access. Correct policy design is explicit and testable.

Homework/Exercises

  1. Find an AVC denial and map it to an allow rule.
  2. Write a minimal policy module that grants only one permission.

Solutions to Homework/Exercises

  1. Use ausearch -m avc and extract scontext, tcontext, class, perm.
  2. Create a .te file with a single allow and compile with checkmodule.

Concept 4: Domain Transitions and Entrypoints

Fundamentals

Domain transitions are how SELinux changes a process type when a program is executed. A process starts in some domain (e.g., init_t), executes a binary labeled with a specific type (e.g., httpd_exec_t), and transitions to a new domain (e.g., httpd_t). This is controlled by type_transition rules and entrypoint permissions. Domain transitions allow you to confine services even when they start from privileged processes. Without transitions, SELinux would not be able to separate different services running under the same Unix user. Transitions are also the reason why labeling binaries correctly is critical.

Transitions are policy-driven, not user-driven. It does not matter if root starts the process; the transition only happens if the executable label and policy rules allow it. This is why service startup mechanisms (systemd units, init scripts) and executable labels are essential pieces of SELinux confinement.

Deep Dive

When a process calls execve, the kernel loads a new program image. SELinux uses this moment to determine whether a domain transition should occur. The transition is driven by three elements: the current process type (source), the label of the executable file (target), and a policy rule that declares the resulting domain. A type_transition rule specifies that a given source type executing a given executable type results in a new process type. For example: type_transition init_t httpd_exec_t : process httpd_t;.

However, a type_transition rule alone is not enough. You must also allow the source domain to execute the binary and allow the new domain to use the binary as an entrypoint. This typically requires rules like allow init_t httpd_exec_t:file { execute }; and allow httpd_t httpd_exec_t:file { entrypoint };. The combination ensures that the system only transitions when it is safe and intended. If any piece is missing, the transition fails and the process runs in the original domain or is denied entirely. This is a common source of confusion when custom services fail to start.

Domain transitions also occur for scripts and interpreters. If you launch a Python script from a confined domain, the actual executable is python, so the transition depends on the label of python and on policy for interpreter domains. This is why SELinux policies often include specialized domains for scripts, and why using initrc_exec_t or bin_t labels incorrectly can have surprising effects.

Transitional types are also used to control privilege escalation or role changes. When a user logs in, the login process (e.g., sshd_t) may transition into a user domain based on the SELinux user mapping and role. The role_transition rule can be used to control which roles a user can enter. Although targeted policies are less strict on roles, MLS policies rely heavily on roles.

Systemd adds another layer: it can execute services with specific SELinux contexts via unit files and SELinuxContext= directives. If the unit file label is wrong or the service binary lacks the expected label, the transition may not occur, leaving the service in an unconfined or unexpected domain. This is a common cause of "it works on one host but not another" behavior.

Understanding transitions is essential for writing policy modules for new services. A typical policy module defines an executable type, a process domain, and the necessary transitions. This is the core of Project 3, where you create a custom policy module for your application. It is also critical in container contexts, where processes inside containers should transition into container_t or spc_t based on container configuration. In Project 5, you will examine how container runtimes assign labels and how --security-opt affects process types.

The subtlety is that transitions can be default or explicit. In some policies, a process might not transition without an explicit type_transition, which can lead to denials that look unrelated. The only reliable way to debug is to inspect the current and expected contexts using ps -eZ and ls -Z. Once you see which domain a process is actually in, you can use sesearch to discover whether the transition rule is present.

How This Fits on Projects

Projects 3, 5, 10, and 11 rely on understanding transitions and entrypoints.

Definitions & Key Terms

  • Domain: A process type.
  • Entrypoint: Permission that allows a binary to create a domain.
  • type_transition: Policy rule defining default process type change.

Mental Model Diagram

init_t --exec httpd_exec_t--> httpd_t
         (entrypoint + transition rules)

How It Works (Step-by-Step)

  1. Process executes a binary.
  2. SELinux checks type_transition rules.
  3. If allowed, new process runs under target domain.
  4. If not, execution may be denied or remain in old domain.

Minimal Concrete Example

type httpd_t;
type httpd_exec_t;

allow init_t httpd_exec_t:file { execute };
allow httpd_t httpd_exec_t:file { entrypoint };
type_transition init_t httpd_exec_t:process httpd_t;

Common Misconceptions

  • “Labeling the binary is enough.” -> You need transition and entrypoint rules too.
  • “If it runs, it must be in the right domain.” -> Use ps -eZ to confirm.

Check-Your-Understanding Questions

  1. What triggers a domain transition?
  2. Why is entrypoint permission required?
  3. How do you verify a process domain?

Check-Your-Understanding Answers

  1. Executing a labeled binary with a matching transition rule.
  2. It authorizes the binary as the entrypoint for the domain.
  3. ps -eZ or /proc/<pid>/attr/current.

Real-World Applications

  • Confining a custom daemon that starts from systemd.
  • Ensuring container processes run in container_t.

Where You’ll Apply It

  • Projects 3, 5, 10, 11

References

  • SELinux by Example (policy transitions)
  • SELinux Notebook (policy language)

Key Insights

Transitions are the bridge between executables and confined domains; without them, SELinux cannot separate services.

Summary

Domain transitions are how SELinux confines services. They require executable labeling, transition rules, and entrypoint permissions.

Homework/Exercises

  1. Find a service’s executable label and process domain.
  2. Write a transition rule for a dummy service.

Solutions to Homework/Exercises

  1. ls -Z /usr/sbin/httpd and ps -eZ | grep httpd.
  2. Define type_transition in a local module and load it.

Concept 5: Policy Modules, Booleans, and Tooling

Fundamentals

SELinux policy is modular. Instead of editing a monolithic policy file, you create modules (.te files) and load them with semodule. Tools like sepolicy generate can scaffold a policy module for a new service. Booleans are runtime switches that allow controlled policy changes without recompiling. This means you can enable a web server to access network resources or NFS shares by toggling a boolean with setsebool. The right workflow is: try to fix denials with labeling and booleans first, then write custom policy only if needed. Understanding module tooling and booleans gives you safe, reversible control over SELinux behavior.

Modules typically include .te (type enforcement), .if (interfaces), and .fc (file contexts) files. This separation lets you describe access rules, reusable interfaces, and labeling patterns as distinct artifacts. Treating these as versioned configuration files makes policy changes auditable and reproducible.

Deep Dive

Policy modules are the unit of extension for SELinux. A module contains type definitions, rules, and optional interfaces. It is compiled into a .pp package and loaded into the kernel policy store. The typical workflow uses the development Makefile in /usr/share/selinux/devel/Makefile. You write a .te file, run make -f /usr/share/selinux/devel/Makefile mymodule.pp, then load it with semodule -i. This results in a policy change that can be removed or disabled later. This modularity is critical in enterprise environments where change control is required.

sepolicy generate is a helper that scaffolds a policy for a new service domain. It creates .te, .if, and .fc files, plus a helper script and spec file. This makes it easier to start from a correct baseline rather than writing from scratch. However, generated policy is only a starting point; it must be refined based on real denials and least-privilege principles. This is why Project 3 walks you through building a policy module and iterating with audit logs.

Booleans are another mechanism for policy adaptation. They allow parts of the policy to be toggled at runtime. For example, httpd_can_network_connect controls whether the HTTP domain can make outbound network connections. This is valuable because it provides flexibility without policy recompilation. Booleans are not a replacement for policy writing, but they are a safer first step. The key discipline is to document and automate boolean changes so they do not become undocumented exceptions.

Managing booleans is done with getsebool, setsebool, and semanage boolean. setsebool -P persists changes across reboots. This persistence is both useful and dangerous; in production, you must track boolean changes as configuration. The sepolicy booleans tool can explain what a boolean does, which is critical when troubleshooting. Many SELinux denials can be solved by toggling the correct boolean rather than writing a new policy rule.

Under the hood, booleans are compiled as conditional blocks in policy. Changing a boolean flips those conditional rules on or off inside the kernel policy store; no reload is required. This means booleans are extremely fast to change, but they also bypass the usual change-review process if not managed carefully. In serious environments, boolean changes should be tracked like code: stored in configuration management, logged, and reviewed. A good practice is to export boolean states (getsebool -a) and version-control them alongside other system baselines. You can also query persistent booleans with semanage boolean -l to confirm what will survive a reboot.

Modules also have priority and dependencies. Policy store can include multiple modules that define overlapping rules; priority determines which module wins if there is a conflict. This is rare but important when layering vendor policies with site-specific modules. Tools like semodule -l, semodule -X, and semodule --disable let you inspect and control module ordering. Project 8 will use these concepts to surface unexpected rule changes.

A mature SELinux workflow uses both modules and booleans. Booleans are for known, supported deviations (like allowing httpd to use NFS). Modules are for new applications. Tools like semodule -l, semodule -r, and semodule -d let you list, remove, or disable modules. If a change breaks something, you can roll it back safely. This is why Project 8 (policy diff) and Project 9 (Ansible hardening role) are essential: they teach you to treat SELinux configuration as code.

How This Fits on Projects

Projects 3, 4, 8, 9, and Final rely on policy modules and booleans.

Definitions & Key Terms

  • Policy module: Compiled policy package loaded into SELinux.
  • Boolean: Runtime toggle for conditional policy rules.
  • sepolicy generate: Tool to scaffold module files.

Mental Model Diagram

.te file -> checkmodule -> .mod -> semodule_package -> .pp -> semodule -i
boolean -> setsebool -P -> policy toggle -> immediate effect

How It Works (Step-by-Step)

  1. Write a module .te file.
  2. Compile into .pp.
  3. Load with semodule -i.
  4. Toggle booleans to adjust policy behavior.

Minimal Concrete Example

# Toggle a boolean
$ getsebool httpd_can_network_connect
$ setsebool -P httpd_can_network_connect on

# Build and load a module
$ make -f /usr/share/selinux/devel/Makefile myapp.pp
$ semodule -i myapp.pp

Common Misconceptions

  • “Booleans are temporary.” -> Not if you use -P.
  • “audit2allow is the best way to write policy.” -> It should be used cautiously.

Check-Your-Understanding Questions

  1. When should you use a boolean instead of a custom module?
  2. What does semodule -i do?
  3. How do you rollback a module?

Check-Your-Understanding Answers

  1. When the policy already supports the change via a boolean.
  2. Installs a compiled policy package.
  3. semodule -r <name> or disable it with -d.

Real-World Applications

  • Enabling HTTP to access NFS with a boolean.
  • Deploying a custom policy module for a SaaS daemon.

Where You’ll Apply It

  • Projects 3, 4, 8, 9, Final

References

  • Red Hat SELinux booleans documentation
  • Red Hat sepolicy generate documentation

Key Insights

Booleans are safe toggles; modules are permanent extensions. Use the right tool for the change.

Summary

SELinux policy is modular and adjustable at runtime. Proper tooling lets you make changes safely and reversibly.

Homework/Exercises

  1. List all booleans containing httpd.
  2. Generate a stub policy with sepolicy generate and inspect the files.

Solutions to Homework/Exercises

  1. getsebool -a | grep httpd.
  2. sepolicy generate --init /usr/sbin/myapp and review output.

Concept 6: Audit, AVC Denials, and Troubleshooting Workflow

Fundamentals

SELinux denials are logged as AVC messages in audit logs. These messages contain the subject context, object context, class, and permission that was denied. Tools like ausearch, aureport, and sealert help you find and interpret these denials. audit2allow can generate policy rules from denials, but it must be used carefully. The right troubleshooting workflow is: confirm the denial, inspect labels, check for existing booleans, and only then consider a custom policy module. Mastering this workflow is the difference between disabling SELinux and fixing it correctly.

Remember that SELinux can operate in enforcing or permissive modes. In permissive mode, denials are logged but not blocked, which is useful for analysis. You can even set a single domain to permissive with semanage permissive -a, keeping the rest of the system enforcing. Understanding these modes makes troubleshooting safer and less disruptive.

Deep Dive

When SELinux denies access, it emits an AVC message in /var/log/audit/audit.log. This message is structured and includes the process (comm), the process context (scontext), the object context (tcontext), the object class (tclass), and the denied permission ({ read }). This is enough information to map the denial to a policy rule. However, logs are verbose; you need tooling to filter them. ausearch lets you query audit logs by time, message type, or command name. aureport summarizes denials. sealert provides human-readable explanations and suggested fixes. These are essential when you are troubleshooting in production.

audit2why explains why access was denied. It analyzes the denial and attempts to match it against known policy constraints. audit2allow can generate allow rules or even a full policy module. This is powerful but dangerous. The generated policy might allow too much. For example, if a process writes to a directory with the wrong label, audit2allow might grant write permission, but the correct fix is to relabel the directory. This is why best practice is: (1) check labeling, (2) check booleans, (3) check expected policy behavior, (4) only then generate rules.

The audit2allow tool focuses on generating Type Enforcement allow rules from observed denials; it does not evaluate whether a labeling fix would be safer. Treat its output as a draft and always review it against least-privilege goals.

When you do generate a policy module, use audit2allow -M mymodule to produce a compiled module and inspect the .te file before loading. Treat this as a hypothesis, not a final fix. Tools like sealert (from setroubleshoot) provide higher-level diagnostics, often suggesting specific booleans or relabeling steps. In enterprise setups, setroubleshootd can send alerts to syslog or email, which is useful for centralized monitoring. This is exactly the data you will aggregate in the Final project.

Permissive domains are another subtle tool. Instead of turning off SELinux globally, you can set only a single domain to permissive (semanage permissive -a myapp_t) to capture denials without breaking production. This gives you the evidence you need to write a tight policy module while keeping the rest of the system protected. Once policy is correct, remove the permissive setting and return to enforcement.

Another important troubleshooting step is verifying the runtime context. Sometimes the denial is caused by the process running in the wrong domain because a transition failed. ps -eZ shows the domain. Similarly, file labels may drift because of incorrect copies or mounts. ls -Z and matchpathcon help identify whether a file label matches policy defaults. restorecon can fix drift.

When debugging, treat denials as signals. Each denial answers: “SELinux would allow this if there were a rule.” The question is whether the action should be allowed. If yes, what is the least-privilege change? That might be a boolean or a file label. If no, then the denial is a security win. In production, you may want to set dontaudit rules for noisy but harmless denials, but only after verifying that they are not hiding real issues.

Project 2 builds an AVC analyzer to parse and categorize denials. Project 6 checks file contexts to reduce denials caused by drift. Project 8 compares policy versions to find regressions. The Final project aggregates denials across hosts to provide remediation at scale. This is the operational heart of SELinux.

How This Fits on Projects

Projects 2, 6, 8, 9, and Final require a strong troubleshooting workflow.

Definitions & Key Terms

  • AVC: Access Vector Cache (and denial messages).
  • auditd: Audit daemon that logs SELinux events.
  • ausearch: Tool to search audit logs.
  • audit2allow: Tool to generate policy rules from denials.

Mental Model Diagram

Denial -> audit.log -> ausearch -> analyze -> relabel/boolean/policy

How It Works (Step-by-Step)

  1. Observe a denial in logs.
  2. Extract scontext, tcontext, class, permission.
  3. Check if labels are correct.
  4. Check for available booleans.
  5. If necessary, write a minimal policy rule.

Minimal Concrete Example

# Find recent AVC denials
$ ausearch -m avc -ts recent

# Explain why denied
$ audit2allow -w -a

Common Misconceptions

  • “audit2allow is the correct fix.” -> It may overgrant.
  • “No AVCs means SELinux is fine.” -> You might be in permissive or disabled mode.

Check-Your-Understanding Questions

  1. What fields in an AVC message map to an allow rule?
  2. Why is audit2allow risky in production?
  3. How do you verify if SELinux is enforcing?

Check-Your-Understanding Answers

  1. scontext (source), tcontext (target), tclass, permission.
  2. It can create overly permissive rules.
  3. getenforce or sestatus.

Real-World Applications

  • Diagnosing a service failing to start after a config change.
  • Identifying mislabeled application data directories.

Where You’ll Apply It

  • Projects 2, 6, 8, 9, Final

References

  • Red Hat SELinux troubleshooting guide
  • audit2allow man page

Key Insights

AVC denials are structured clues, not noise. Read them correctly and SELinux becomes predictable.

Summary

Troubleshooting SELinux means reading AVCs, checking labels and booleans, and applying the minimal fix.

Homework/Exercises

  1. Trigger a denial and parse it into a pseudo-allow rule.
  2. Use sealert to interpret a denial.

Solutions to Homework/Exercises

  1. Use ausearch and extract fields manually.
  2. Run sealert -a /var/log/audit/audit.log.

Concept 7: MLS/MCS and Container or VM Isolation

Fundamentals

Multi-Level Security (MLS) and Multi-Category Security (MCS) add sensitivity levels and categories to SELinux contexts. MLS enforces strict information flow rules such as “no read up” and “no write down” (Bell-LaPadula). MCS is a practical variant that uses categories to isolate workloads like containers or VMs. In container environments, the process type is often the same (container_t), so isolation relies on MCS categories to prevent cross-container access. Understanding MLS/MCS is essential for high-assurance systems, container security, and multi-tenant isolation.

Categories are sets, not single labels. A process can have multiple categories (e.g., c10,c24), and access is allowed only when the category sets match or dominate according to policy. MLS uses dominance rules across hierarchical levels; MCS uses category equality to enforce separation. This distinction matters when you design isolation schemes.

Deep Dive

MLS adds a structured hierarchy of sensitivity levels (s0, s1, s2, etc.) and enforces mandatory access rules. The Bell-LaPadula model is a classic example: a subject at a high level cannot write down to a lower level, and a subject at a low level cannot read up. This prevents data leakage across classification levels. SELinux implements MLS through the level field in the security context. In MLS environments, the level is not just s0; it includes ranges and categories. This is common in government or compliance environments where data classification is enforced.

MCS is a simplified, category-based model that does not assign meaning to categories beyond separation. Categories are numbered (e.g., c1, c2, c3). Many policies provide a large category range (commonly c0-c1023), enabling a very large number of unique category sets for isolation. A process and file can have the same type but different categories; access is allowed only if categories match. This is how containers and virtualization use SELinux: each container is assigned a unique category set (s0:c123,c456), and files created by that container carry the same label. Even if all containers run as container_t, their categories differ, preventing cross-container access.

This is a powerful mechanism for multi-tenant isolation. It is lightweight because it avoids large numbers of types. The category space is large enough for typical fleets, but it is not infinite; very large environments must manage category reuse carefully. Tools like Podman and container runtimes automatically manage MCS labels; options like :Z and :z control whether volumes get private or shared labels.

In virtualization, sVirt applies the same idea to QEMU processes and VM disk images. Each VM is labeled with a unique category set so that one VM cannot access another VM’s disk image even if they share the same type. This is a critical defense against VM escape paths that rely on shared storage. SELinux booleans like virt_use_nfs or virt_use_usb can widen the access of virtualization domains, so they must be managed carefully. Similarly, containers running in privileged mode may transition into spc_t, which is effectively unconfined; your monitoring should flag those cases. Understanding these edge cases is crucial when you operate container platforms at scale.

Category enforcement can also cause "mysterious" denials because the TE rule looks correct but the categories do not match. In those cases, the denial is about MLS/MCS levels, not types. When debugging, check the scontext and tcontext levels, and test by temporarily aligning categories in a lab environment to confirm the root cause.

MLS and MCS also appear in virtualization via sVirt. Virtual machines are labeled with categories so that disk images and QEMU processes only interact when categories match. This prevents one VM from accessing another’s disk even if they share the same type. In SELinux, categories act as a form of tenant ID.

In Project 10, you will implement a classification demo that enforces MLS rules. In Project 5, you will examine container labels and observe how MCS isolates volumes. In the Final project, you will track MCS labels across a fleet and detect when privileged containers are running with spc_t, which disables category enforcement.

How This Fits on Projects

Projects 5, 10, and the Final project rely on MLS/MCS concepts.

Definitions & Key Terms

  • MLS: Multi-Level Security with hierarchical levels.
  • MCS: Multi-Category Security using category sets.
  • sVirt: SELinux virtualization isolation using MCS.
  • container_t: Common process type for containers.

Mental Model Diagram

Process: container_t:s0:c12,c57
File:    container_file_t:s0:c12,c57
Access allowed only if categories match

How It Works (Step-by-Step)

  1. Assign categories to process and file.
  2. Policy enforces category dominance rules.
  3. Access allowed only with matching categories.

Minimal Concrete Example

# Run a container with private label
$ podman run -v /data:/data:Z busybox ls -Z /data

Common Misconceptions

  • “Type enforcement alone isolates containers.” -> MCS categories are essential.
  • “MLS is the same as MCS.” -> MLS is hierarchical, MCS is categorical isolation.

Check-Your-Understanding Questions

  1. What does s0:c1,c2 represent?
  2. Why is MCS needed for containers?
  3. How do categories affect access decisions?

Check-Your-Understanding Answers

  1. Sensitivity level s0 with categories c1 and c2.
  2. Because container processes share the same type.
  3. Access is allowed only when the object’s category set matches (or is a subset of) the subject’s categories, per policy rules.

Real-World Applications

  • Container isolation in Kubernetes and Podman.
  • VM isolation via sVirt.

Where You’ll Apply It

  • Projects 5, 10, Final

References

  • Red Hat container SELinux labeling guidance
  • AOSP SELinux documentation

Key Insights

MCS adds a lightweight tenant boundary when types alone are too coarse.

Summary

MLS enforces strict security levels; MCS isolates tenants with categories, especially for containers and VMs.

Homework/Exercises

  1. Inspect the MCS label of a running container.
  2. Compare labels of two containers and their volumes.

Solutions to Homework/Exercises

  1. podman exec <id> cat /proc/self/attr/current.
  2. ls -Z on volumes mounted with :Z vs :z.

Glossary

  • AVC: Access Vector Cache; cache and denial messages for SELinux decisions.
  • Domain: A process type in SELinux.
  • Entrypoint: Permission allowing a binary to create a domain.
  • MLS: Multi-Level Security enforcing hierarchical data separation.
  • MCS: Multi-Category Security for tenant isolation.
  • Policy module: A compiled policy package loaded into SELinux.
  • Role: SELinux RBAC element that restricts domain transitions.
  • Type: Primary identity used in TE rules.

Why SELinux Matters

The Modern Problem It Solves

Modern systems run complex services with massive attack surfaces. If a service is exploited under DAC, the process can access anything that Unix permissions allow. SELinux enforces default deny at the kernel level so compromised processes remain confined. This changes the security model from “trust the user” to “trust only explicit policy”.

Modern impact signals (with sources):

  • Default deny policy model is explicitly stated in Android’s SELinux documentation. (Source: AOSP SELinux docs, updated 2025)
  • Android 5.0+ fully enforcing across more than 60 domains shows large-scale MAC enforcement in consumer devices. (Source: AOSP SELinux docs, Android 5.0 / 2014)
  • MCS categories provide ~500,000 unique combinations for container isolation using 1024 categories. (Source: Red Hat blog on SELinux for containers, 2020)
DAC Model (Old)                    SELinux MAC Model (New)
┌─────────────────────────┐       ┌──────────────────────────┐
│ user permissions only   │       │ type + policy required   │
│ compromise => full user │       │ compromise => confined   │
└─────────────────────────┘       └──────────────────────────┘

Context & Evolution (History)

SELinux originated from research into mandatory access controls and was integrated into Linux via the LSM framework. Its adoption in enterprise Linux distributions and Android demonstrates that MAC is not only theoretical but essential in large-scale deployments.


Concept Summary Table

Concept Cluster What You Need to Internalize
Architecture & LSM Where decisions happen, how AVC caches, and how policy is enforced in kernel
Security Contexts & Labeling Context format, label storage, and relabeling workflow
Type Enforcement How allow rules are structured and applied
Domain Transitions How process labels change across exec and entrypoints
Policy Modules & Booleans How to safely extend or toggle policy
Audit & Troubleshooting Reading AVCs, using tools, and fixing root causes
MLS/MCS Isolation Classification rules and container/VM isolation

Project-to-Concept Map

Project What It Builds Primer Concepts It Uses
Project 1: Context Explorer Context visualization and labeling insight Concepts 1, 2
Project 2: AVC Analyzer AVC parsing and remediation workflow Concepts 1, 6
Project 3: Policy Module Builder Custom policy module for an app Concepts 3, 4, 5
Project 4: Boolean Manager Boolean discovery and safe toggling Concepts 5, 6
Project 5: Container Sandbox Lab MCS and container labeling Concepts 2, 7
Project 6: File Context Checker Detect drift and relabel Concepts 2, 6
Project 7: Port Security Auditor Port label auditing Concepts 2, 3
Project 8: Policy Diff Tool Detect rule changes and regressions Concepts 3, 5, 6
Project 9: Ansible Hardening Role Fleet-wide SELinux config Concepts 2, 5, 6
Project 10: MLS/MCS Demo Classification enforcement Concepts 2, 7
Project 11: Kernel Inspector LSM hooks and AVC internals Concepts 1, 3, 4
Project 12: Enterprise Platform End-to-end SELinux ops All concepts

Deep Dive Reading by Concept

Fundamentals & Architecture

Concept Book & Chapter Why This Matters
SELinux architecture SELinux by Example (Ch. 1-2) Mental model of policy and enforcement
LSM framework The Linux Programming Interface (Security chapters) Kernel interfaces and security hooks
Access control models Operating Systems: Three Easy Pieces (Security/Protection chapters) MAC vs DAC foundations

Policy & Tooling

Concept Book & Chapter Why This Matters
Type enforcement SELinux System Administration (Policy chapters) Core rule language
Policy modules SELinux Notebook (Policy module sections) Practical module creation
Booleans Red Hat SELinux Guide (Booleans sections) Safe runtime changes

Troubleshooting & Operations

Concept Book & Chapter Why This Matters
AVC analysis SELinux System Administration (Troubleshooting chapters) Systematic denial analysis
Audit tools The Linux Programming Interface (Audit/logging sections) Log parsing and automation

Advanced Topics

Concept Book & Chapter Why This Matters
MLS/MCS SELinux by Example (MLS/MCS chapters) Classification and isolation
Containers and sVirt Red Hat SELinux Docs (Containers sections) Real-world isolation patterns

Quick Start

Day 1 (4 hours):

  1. Read Concept 1 and Concept 2 in the Theory Primer.
  2. Run sestatus, getenforce, ls -Z /.
  3. Start Project 1 and build the first context visualization.

Day 2 (4 hours):

  1. Start Project 2 and parse real AVC logs.
  2. Trigger a denial intentionally (mislabel a directory) and fix it.
  3. Skim Concept 6 (Audit/Troubleshooting).

End of Weekend: You can read contexts, interpret AVCs, and fix a basic labeling issue without disabling SELinux.


Best for: Sysadmins, SREs, and DevOps engineers

  1. Project 1 (Context Explorer)
  2. Project 2 (AVC Analyzer)
  3. Project 6 (File Context Checker)
  4. Project 9 (Ansible Hardening Role)
  5. Final Project

Path 2: The Policy Developer

Best for: Engineers writing custom policies

  1. Project 1
  2. Project 3 (Policy Module Builder)
  3. Project 8 (Policy Diff Tool)
  4. Project 11 (Kernel Inspector)

Path 3: The Container Security Path

Best for: Container and Kubernetes users

  1. Project 5 (Container Lab)
  2. Project 7 (Port Security Auditor)
  3. Project 10 (MLS/MCS Demo)
  4. Final Project

Path 4: The Completionist

Complete projects in order, 1 through 12, over 3-6 months.


Success Metrics

  • You can read any AVC denial and explain the missing rule.
  • You can relabel files correctly without chcon hacks.
  • You can create and load a minimal policy module for a new service.
  • You can explain how container isolation works under MCS.
  • You can automate SELinux configuration across multiple hosts.

Project Overview Table

ID Project Difficulty Time Core Concepts
1 SELinux Context Explorer & Visualizer Beginner Weekend 1, 2
2 AVC Denial Analyzer & Auto-Fixer Intermediate 1-2 weeks 1, 6
3 Custom Application Policy Module Builder Advanced 2-3 weeks 3, 4, 5
4 SELinux Boolean Manager Intermediate 1-2 weeks 5, 6
5 Container SELinux Sandbox Lab Advanced 2-3 weeks 2, 7
6 File Context Integrity Checker Intermediate 1-2 weeks 2, 6
7 Network Port Security Auditor Intermediate 1-2 weeks 2, 3
8 SELinux Policy Diff Tool Advanced 2-3 weeks 3, 5, 6
9 Ansible SELinux Hardening Role Intermediate 1-2 weeks 2, 5, 6
10 MLS/MCS Classification Demo Expert 3-4 weeks 7
11 SELinux Kernel Inspector Master 1-2 months 1, 3, 4
12 Enterprise SELinux Security Platform Expert 2-3 months All

Project List

Project 1: SELinux Context Explorer & Visualizer

  • Main Programming Language: Python
  • Alternative Programming Languages: Go, Rust
  • Coolness Level: Level 2: “Oh, I see it now”
  • Business Potential: 1. The “Internal Tool”
  • Difficulty: Level 1: Beginner
  • Knowledge Area: SELinux Labels and Contexts
  • Software or Tool: libselinux, ls -Z, ps -eZ
  • Main Book: “SELinux System Administration” by Sven Vermeulen

What you’ll build: A CLI tool that scans processes, files, and ports and outputs a structured map of SELinux contexts. It should render a simple ASCII visualization showing which process types touch which file types.

Why it teaches SELinux: You cannot debug what you cannot see. This project forces you to read contexts fluently.

Core challenges you’ll face:

  • Parsing SELinux labels -> map to context components
  • Mapping processes to resources -> understand how services interact with files
  • Presenting context drift -> detect mismatches from default labels

Real World Outcome

You run your tool and see a clear map of SELinux contexts on your system:

$ selctx map --process httpd

Process: httpd_t (PID 2134)
  Reads:
    httpd_sys_content_t  -> /var/www/html/index.html
  Writes:
    httpd_log_t          -> /var/log/httpd/access_log
  Denied:
    shadow_t             -> /etc/shadow

Context Summary:
  system_u:system_r:httpd_t:s0  (process)
  system_u:object_r:httpd_sys_content_t:s0  (content)
  system_u:object_r:httpd_log_t:s0  (logs)

# Detect label drift for a directory
$ selctx drift /srv/www
MISMATCH: /srv/www/app.conf
  current: system_u:object_r:default_t:s0
  expected: system_u:object_r:httpd_sys_content_t:s0

# Suggested remediation
$ selctx fix /srv/www/app.conf
restorecon -v /srv/www/app.conf

The Core Question You’re Answering

“What does SELinux actually see when it decides whether something is allowed?”

Concepts You Must Understand First

  1. Security Context Format
    • What does user:role:type:level mean?
    • Book Reference: SELinux System Administration, Ch. 2
  2. Label Storage
    • Where are file labels stored?
    • Book Reference: SELinux Notebook, Labeling section
  3. Process Domains
    • How does a process get its type?
    • Book Reference: SELinux by Example, Ch. 2

Questions to Guide Your Design

  1. How will you map process types to files they access?
  2. How will you detect mismatched labels vs expected defaults?
  3. How will you render the relationships in a readable way?

Thinking Exercise

Imagine a process httpd_t reads a file labeled user_home_t and is denied. Should your tool report this as:

  • Label drift (file mislabeled)?
  • Policy issue (needs allow rule)?
  • Boolean toggle (httpd_enable_homedirs)?

The Interview Questions They’ll Ask

  1. “What is a SELinux context and which field matters most for TE?”
  2. “Why does SELinux care about file labels if DAC already exists?”
  3. “How do you determine whether a label is correct?”
  4. “What’s the difference between process context and file context?”

Hints in Layers

Hint 1: Start with ps -eZ and ls -Z

ps -eZ | head
ls -Z /var/www/html

Hint 2: Use libselinux bindings

import selinux
selinux.getfilecon('/var/www/html/index.html')

Hint 3: Match default labels

matchpathcon -V /var/www/html/index.html

Books That Will Help

Topic Book Chapter
Contexts “SELinux System Administration” Ch. 2
Labeling “SELinux Notebook” Labeling sections
Troubleshooting “SELinux by Example” Ch. 4

Common Pitfalls & Debugging

Problem: “My tool shows no contexts”

  • Why: SELinux may be disabled or filesystem not labeled
  • Fix: sestatus and fixfiles onboot
  • Quick test: getenforce

Problem: “Labels don’t match defaults”

  • Why: Files were copied without preserving context
  • Fix: restorecon -Rv <path>
  • Verification: matchpathcon -V <path>

Definition of Done

  • Tool lists contexts for processes, files, and ports
  • Can detect mismatched labels vs defaults
  • Generates a readable summary for a given service
  • Output includes clear mapping of source/target types

Project 2: AVC Denial Analyzer & Auto-Fixer

  • Main Programming Language: Python
  • Alternative Programming Languages: Go, Rust
  • Coolness Level: Level 3: “I fix SELinux without fear”
  • Business Potential: 2. The “SRE Toolkit”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: SELinux Troubleshooting
  • Software or Tool: ausearch, audit2why, sealert
  • Main Book: “SELinux System Administration” by Sven Vermeulen

What you’ll build: A CLI tool that parses AVC denials, groups them by root cause, and proposes the safest remediation (relabel, boolean, or policy module).

Why it teaches SELinux: You learn to interpret the audit log as a policy query, not just errors.

Core challenges you’ll face:

  • Parsing AVC messages -> map to allow-rule structure
  • Categorizing fixes -> labeling vs boolean vs policy
  • Explaining denials -> human-readable reasoning

Real World Outcome

$ avcfix analyze --since "1h"

Found 12 AVC denials (grouped into 3 root causes):

1) Label mismatch: /opt/myapp/logs (expected var_log_t)
   - Fix: semanage fcontext -a -t var_log_t "/opt/myapp/logs(/.*)?"
   - Apply: restorecon -Rv /opt/myapp/logs

2) Boolean required: httpd_can_network_connect
   - Fix: setsebool -P httpd_can_network_connect on

3) Missing policy rule for myapp_t -> var_run_t:dir write
   - Fix: create local policy module (generated suggestion in ./policy)

# Raw AVC example (for traceability)
$ ausearch -m avc -ts recent | head -1
type=AVC msg=audit(1700000000.123:456): avc:  denied  { write } for  pid=2451 comm="myapp" \
scontext=system_u:system_r:myapp_t:s0 tcontext=system_u:object_r:var_run_t:s0 tclass=dir

# Auto-generated module preview
$ avcfix generate --module myapp_avc
Wrote myapp_avc.te (review before installing)

The Core Question You’re Answering

“What is the minimal, safest fix for an SELinux denial?”

Concepts You Must Understand First

  1. AVC message fields
    • scontext, tcontext, tclass, perms
    • Book Reference: SELinux System Administration, Ch. 5
  2. Labeling workflow
    • semanage fcontext and restorecon
    • Book Reference: SELinux Notebook
  3. Booleans
    • setsebool and getsebool
    • Book Reference: Red Hat SELinux Guide

Questions to Guide Your Design

  1. How will you parse AVC logs reliably?
  2. How will you decide whether a boolean exists for a denial?
  3. How will you avoid generating unsafe policy modules?

Thinking Exercise

If httpd_t is denied writing to /var/www/html/uploads, which is more correct:

  • Add allow rule for httpd_t -> httpd_sys_content_t:dir write
  • Label the directory as httpd_sys_rw_content_t Why?

The Interview Questions They’ll Ask

  1. “Explain the fields in an AVC denial.”
  2. “Why is relabeling often better than allowing?”
  3. “When should you write a custom policy?”
  4. “What does audit2why do?”

Hints in Layers

Hint 1: Use ausearch

ausearch -m avc -ts recent

Hint 2: Parse with regex

# extract scontext, tcontext, tclass, perms

Hint 3: Map to rule skeleton

allow <scontext_type> <tcontext_type>:<class> { <perm> };

Books That Will Help

Topic Book Chapter
Troubleshooting “SELinux System Administration” Ch. 5
Audit logs “The Linux Programming Interface” Audit sections
Policy basics “SELinux by Example” Ch. 3

Common Pitfalls & Debugging

Problem: “Denials are missing”

  • Why: SELinux may be permissive or auditd not running
  • Fix: getenforce, systemctl status auditd
  • Quick test: trigger a denial and check audit.log

Problem: “Generated policy is too broad”

  • Why: audit2allow includes unrelated denials
  • Fix: filter by comm or path
  • Quick test: ausearch -m avc -c myapp

Definition of Done

  • Parses AVC logs and groups by root cause
  • Suggests labeling and boolean fixes when possible
  • Generates minimal policy skeletons only when needed
  • Outputs a human-readable remediation report

Project 3: Custom Application Policy Module Builder

  • Main Programming Language: C / M4
  • Alternative Programming Languages: Python (policy generation tooling)
  • Coolness Level: Level 4: “I write policy”
  • Business Potential: 2. The “Internal Security Platform”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: SELinux Policy Development
  • Software or Tool: checkmodule, semodule, sepolicy
  • Main Book: “SELinux by Example” by Frank Mayer et al.

What you’ll build: A policy module that confines a custom daemon, including file contexts and domain transitions.

Why it teaches SELinux: Writing policy forces you to understand TE rules and transitions deeply.

Core challenges you’ll face:

  • Defining new types -> application domain and file types
  • Creating transitions -> from init or systemd
  • Testing least privilege -> avoid over-permission

Real World Outcome

$ semodule -i myapp.pp
$ systemctl start myapp
$ ps -eZ | grep myapp
system_u:system_r:myapp_t:s0  2441 ? 00:00:00 myapp

# Verify policy rules exist
$ sesearch -A -s myapp_t -t myapp_log_t -c file | head -1
allow myapp_t myapp_log_t:file { open read write append getattr };

# Verify denials are resolved
$ ausearch -m avc -c myapp -ts recent
<no AVC denials in the last 10 minutes>

The Core Question You’re Answering

“How do I confine a new service with the minimum privileges it needs?”

Concepts You Must Understand First

  1. Type Enforcement rules
    • allow rule structure
    • Book Reference: SELinux by Example, Ch. 3
  2. Domain transitions
    • entrypoint and type_transition
    • Book Reference: SELinux by Example, Ch. 4
  3. Policy modules
    • compile and load
    • Book Reference: SELinux Notebook, modules section

Questions to Guide Your Design

  1. What file types does your app need to read/write?
  2. What binaries should be entrypoints for the domain?
  3. Which permissions are truly required vs convenient?

Thinking Exercise

Your app needs to write logs. Would you:

  • Allow myapp_t to write to var_log_t globally?
  • Create a specific log type myapp_log_t and label the directory?

The Interview Questions They’ll Ask

  1. “What is the difference between a file type and a process domain?”
  2. “How does type_transition work?”
  3. “Why is least privilege important in SELinux policy?”
  4. “What does semodule -i do?”

Hints in Layers

Hint 1: Generate a scaffold

sepolicy generate --init /usr/sbin/myapp

Hint 2: Compile with the SELinux Makefile

make -f /usr/share/selinux/devel/Makefile myapp.pp

Hint 3: Load and test

semodule -i myapp.pp
systemctl restart myapp

Books That Will Help

Topic Book Chapter
Policy basics “SELinux by Example” Ch. 3-4
Modules “SELinux Notebook” Module sections
System services “The Linux Programming Interface” Service management sections

Common Pitfalls & Debugging

Problem: “Service stays in init_t”

  • Why: transition rule missing
  • Fix: add type_transition and entrypoint
  • Verification: ps -eZ

Problem: “Policy loads but service fails”

  • Why: missing allow rules for required resources
  • Fix: analyze AVC denials and add minimal rules
  • Quick test: ausearch -m avc -c myapp

Definition of Done

  • Service runs in a custom domain (myapp_t)
  • Files are labeled with custom types
  • Only required permissions are granted
  • Policy module loads cleanly and can be removed

Project 4: SELinux Boolean Manager with Web Dashboard

  • Main Programming Language: Python (Flask)
  • Alternative Programming Languages: Go, Node
  • Coolness Level: Level 3: “Production-ready tool”
  • Business Potential: 2. The “Admin UX”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: SELinux Policy Management
  • Software or Tool: getsebool, setsebool, sepolicy
  • Main Book: “SELinux System Administration”

What you’ll build: A web UI to view, filter, and toggle SELinux booleans, with audit logging and safe defaults.

Why it teaches SELinux: Booleans are the safest way to modify policy; you must know how they work.

Core challenges you’ll face:

  • Discovering relevant booleans -> mapping to services
  • Persisting changes -> setsebool -P
  • User safety -> prevent enabling risky booleans blindly

Real World Outcome

$ curl http://localhost:8080/booleans/httpd

httpd_can_network_connect: OFF
httpd_enable_homedirs: OFF
httpd_execmem: OFF

Toggle -> httpd_can_network_connect: ON

# Persisted change check
$ getsebool httpd_can_network_connect
httpd_can_network_connect --> on

# Audit trail
$ ausearch -m avc -ts recent | grep setsebool | head -1
type=USER_AVC msg=audit(1700000101.321:987): user pid=3012 msg='boolean httpd_can_network_connect set to 1'

The Core Question You’re Answering

“How can I safely adjust SELinux behavior without writing policy?”

Concepts You Must Understand First

  1. Booleans and conditional policy
    • What does a boolean toggle inside the policy?
    • How do you list and interpret a boolean’s description?
    • Book Reference: SELinux System Administration, Booleans chapter
  2. Persistence and policy store
    • What is the difference between setsebool and setsebool -P?
    • Where are persistent booleans stored?
    • Book Reference: SELinux Notebook, Policy tools sections
  3. Risk analysis of booleans
    • Which booleans weaken confinement (e.g., execmem)?
    • How do you document and audit boolean changes?
    • Book Reference: Red Hat SELinux Guide, Booleans section

Questions to Guide Your Design

  1. How do you list booleans and their descriptions?
  2. How do you prevent risky booleans from being enabled?
  3. How do you audit boolean changes?

Thinking Exercise

Should enabling httpd_execmem be a one-click action? What safeguards would you add?

The Interview Questions They’ll Ask

  1. “What is an SELinux boolean?”
  2. “Why is -P important?”
  3. “What risks do booleans introduce?”
  4. “How would you audit and roll back boolean changes?”

Hints in Layers

Hint 1: List booleans

getsebool -a | grep httpd

Hint 2: Use sepolicy booleans for descriptions

sepolicy booleans -b httpd_execmem

Hint 3: Toggle with persistence

setsebool -P httpd_can_network_connect on

Books That Will Help

Topic Book Chapter
Booleans “SELinux System Administration” Booleans chapter
Policy mgmt “SELinux Notebook” Policy tools sections

Common Pitfalls & Debugging

Problem: “Changes revert after reboot”

  • Why: setsebool without -P
  • Fix: setsebool -P ...

Problem: “Boolean doesn’t exist”

  • Why: Policy not installed or using different distro policy
  • Fix: check selinux-policy version

Problem: “UI shows toggled state but policy didn’t change”

  • Why: missing privileges or failure to persist
  • Fix: run backend as root or use sudo, verify with getsebool

Definition of Done

  • Lists booleans with descriptions
  • Supports safe toggling with confirmation
  • Logs all changes
  • Exports config for automation

Project 5: Container SELinux Sandbox Lab

  • Main Programming Language: Bash / Python
  • Alternative Programming Languages: Go
  • Coolness Level: Level 4: “Container whisperer”
  • Business Potential: 2. The “Security Lab”
  • Difficulty: Level 3: Advanced
  • Knowledge Area: SELinux + Containers
  • Software or Tool: Podman or Docker, container-selinux
  • Main Book: “Container Security” by Liz Rice

What you’ll build: A repeatable lab that demonstrates SELinux MCS isolation between containers, including volume relabeling (:Z vs :z).

Why it teaches SELinux: Containers rely on SELinux categories for isolation when types are the same.

Core challenges you’ll face:

  • Understanding container labels -> container_t, container_file_t
  • Managing MCS categories -> s0:cX,cY
  • Volume relabeling -> private vs shared

Real World Outcome

$ podman run -d --name c1 -v /data:/data:Z alpine sleep 300
$ podman run -d --name c2 -v /data:/data:Z alpine sleep 300

$ ls -Z /data
system_u:object_r:container_file_t:s0:c123,c456 /data

# c2 cannot access c1 data due to MCS mismatch
$ podman exec c2 cat /data/secret.txt
cat: /data/secret.txt: Permission denied

# Inspect container labels
$ podman exec c1 cat /proc/self/attr/current
system_u:system_r:container_t:s0:c123,c456

The Core Question You’re Answering

“How does SELinux prevent containers from attacking each other?”

Concepts You Must Understand First

  1. MCS categories
    • Unique category sets for isolation
    • Book Reference: SELinux by Example, MLS/MCS chapter
  2. Container labels
    • container_t, container_file_t
    • Book Reference: Container Security
  3. Volume relabeling and privileged containers
    • What do :Z and :z change on the host?
    • What does spc_t mean for isolation?
    • Book Reference: Red Hat SELinux containers guide

Questions to Guide Your Design

  1. How does :Z differ from :z?
  2. How do you prove that MCS blocks access?
  3. What happens when you run with --privileged?

Thinking Exercise

If two containers share a volume labeled s0, should they be isolated? Why or why not?

The Interview Questions They’ll Ask

  1. “What is MCS in SELinux?”
  2. “Why does SELinux use categories for containers?”
  3. “How do :Z and :z affect security?”
  4. “What happens when a container runs in privileged mode?”

Hints in Layers

Hint 1: Inspect container labels

podman exec c1 cat /proc/self/attr/current

Hint 2: Use ls -Z on volumes

ls -Z /data

Hint 3: Compare :Z and :z

podman run -v /data:/data:Z ...
podman run -v /data:/data:z ...

Books That Will Help

Topic Book Chapter
Containers “Container Security” SELinux sections
MLS/MCS “SELinux by Example” MLS/MCS chapter

Common Pitfalls & Debugging

Problem: “Container can’t access volume”

  • Why: Missing relabel
  • Fix: use :Z or :z

Problem: “Containers can read each other’s data”

  • Why: Shared category label s0
  • Fix: use private labels or unique categories

Problem: “Privileged container bypasses isolation”

  • Why: container may run as spc_t
  • Fix: avoid privileged containers or monitor for spc_t

Definition of Done

  • Demonstrates MCS isolation with two containers
  • Shows :Z vs :z behavior
  • Documents labels for processes and files

Project 6: File Context Integrity Checker

  • Main Programming Language: Python
  • Alternative Programming Languages: Go
  • Coolness Level: Level 3: “Reliability tool”
  • Business Potential: 2. The “Ops Audit”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Labeling and Drift
  • Software or Tool: matchpathcon, restorecon
  • Main Book: “SELinux System Administration”

What you’ll build: A scanner that compares current file labels to default policy labels and reports drift.

Why it teaches SELinux: Most SELinux problems are labeling problems.

Core challenges you’ll face:

  • Comparing labels -> actual vs expected
  • Safe remediation -> generating restorecon plans

Real World Outcome

$ selctx drift /srv

MISMATCH: /srv/app/config.yaml
  current: system_u:object_r:default_t:s0
  expected: system_u:object_r:myapp_conf_t:s0

Suggested fix:
  restorecon -v /srv/app/config.yaml

# Dry run mode
$ selctx drift /srv --dry-run
Would relabel: /srv/app/config.yaml -> myapp_conf_t

The Core Question You’re Answering

“Which files are mislabeled and causing hidden failures?”

Concepts You Must Understand First

  1. File context database
    • matchpathcon and patterns
    • Book Reference: SELinux Notebook
  2. Restorecon workflow
    • Book Reference: SELinux System Administration
  3. Context inheritance
    • How labels are assigned to new files and directories
    • Book Reference: SELinux by Example, labeling chapter

Questions to Guide Your Design

  1. How do you detect mismatches efficiently?
  2. How do you avoid relabeling critical system files?

Thinking Exercise

If a file is mislabeled but no denials occur, should you fix it?

The Interview Questions They’ll Ask

  1. “What causes label drift?”
  2. “What does restorecon do?”
  3. “Why is default_t a red flag?”
  4. “When should you use semanage fcontext?”

Hints in Layers

Hint 1: Use matchpathcon

matchpathcon -V /path

Hint 2: Use restorecon -n for dry run

restorecon -nRv /srv

Hint 3: List policy file-context rules

semanage fcontext -l | head

Books That Will Help

Topic Book Chapter
Labeling “SELinux System Administration” Labeling chapter
Policy paths “SELinux Notebook” File context sections

Common Pitfalls & Debugging

Problem: “Too many mismatches”

  • Why: Filesystem was mounted without labels
  • Fix: Relabel on boot

Problem: “Relabeling breaks service”

  • Why: Custom file paths not registered
  • Fix: Add semanage fcontext rules

Problem: “Labels revert after reinstall”

  • Why: changes made with chcon only
  • Fix: ensure persistent rules via semanage fcontext

Definition of Done

  • Scans directories for label drift
  • Generates a safe relabel plan
  • Supports dry-run mode

Project 7: Network Port Security Auditor

  • Main Programming Language: Python
  • Alternative Programming Languages: Go
  • Coolness Level: Level 3
  • Business Potential: 2
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: SELinux Port Types
  • Software or Tool: semanage port
  • Main Book: “SELinux System Administration”

What you’ll build: A tool that inspects port labels and verifies that services bind only to expected port types.

Why it teaches SELinux: SELinux controls network access based on port labels, not just numbers.

Core challenges you’ll face:

  • Mapping services to ports
  • Detecting nonstandard port usage

Real World Outcome

$ selport audit

Port 80: http_port_t (httpd_t allowed)
Port 3306: mysqld_port_t (mysqld_t allowed)
Port 9000: unlabeled -> potential policy gap

$ semanage port -a -t http_port_t -p tcp 9000
$ selport audit --port 9000
Port 9000: http_port_t (httpd_t allowed)

The Core Question You’re Answering

“Are my services binding only to ports allowed by policy?”

Concepts You Must Understand First

  1. Port labeling
    • semanage port -l
    • Book Reference: SELinux System Administration
  2. Type enforcement
    • port types in policy
    • Book Reference: SELinux by Example
  3. Service domains
    • Which domains are allowed to bind to which ports
    • Book Reference: SELinux System Administration, networking chapter

Questions to Guide Your Design

  1. How do you map running services to ports?
  2. How do you detect mismatches between service domain and port type?

Thinking Exercise

If a service binds to port 9000 and SELinux denies it, should you relabel the port or change the service?

The Interview Questions They’ll Ask

  1. “How does SELinux control port access?”
  2. “What is semanage port used for?”
  3. “Why do nonstandard ports cause denials?”
  4. “When would you relabel a port vs change a service?”

Hints in Layers

Hint 1: List port labels

semanage port -l | head

Hint 2: Map service to port

ss -lntp

Hint 3: Add a custom port label

semanage port -a -t http_port_t -p tcp 9000

Books That Will Help

Topic Book Chapter
Network SELinux “SELinux System Administration” Networking chapter
TE rules “SELinux by Example” Policy chapters

Common Pitfalls & Debugging

Problem: “Service fails on nonstandard port”

  • Why: Port not labeled
  • Fix: semanage port -a -t http_port_t -p tcp 9000

Problem: “Service binds but logs AVC denials”

  • Why: wrong domain or mislabeled port type
  • Fix: verify ps -eZ and semanage port -l

Definition of Done

  • Reports port labels and service bindings
  • Identifies mismatches and suggests fixes

Project 8: SELinux Policy Diff Tool

  • Main Programming Language: Python
  • Alternative Programming Languages: Go
  • Coolness Level: Level 4
  • Business Potential: 2
  • Difficulty: Level 3: Advanced
  • Knowledge Area: Policy Auditing
  • Software or Tool: sesearch, seinfo
  • Main Book: “SELinux Notebook”

What you’ll build: A tool that compares two policy versions and highlights rule changes, new permissions, and removed constraints.

Why it teaches SELinux: Policy changes are subtle; this tool forces you to understand policy structure.

Core challenges you’ll face:

  • Parsing policy output
  • Detecting impactful changes

Real World Outcome

$ seldiff old_policy.pp new_policy.pp

Changes:
+ allow httpd_t home_root_t:dir { read getattr }
- neverallow unconfined_t shadow_t:file { read }

Summary:
  Added allow rules: 3
  Removed allow rules: 1
  neverallow removed: 1 (HIGH RISK)

The Core Question You’re Answering

“What changed in policy, and does it weaken security?”

Concepts You Must Understand First

  1. Type Enforcement rules
    • How do allow/neverallow rules represent access changes?
    • How do you map AVC fields to rule shape?
    • Book Reference: SELinux by Example, Ch. 3
  2. Policy modules and priority
    • How do modules layer in the policy store?
    • What is module priority and why does it matter?
    • Book Reference: SELinux Notebook, modules section
  3. Policy querying tools
    • What does sesearch show and how do you filter it?
    • Book Reference: SELinux Notebook, policy tools section

Questions to Guide Your Design

  1. How do you normalize rule order for comparison?
  2. How do you flag high-risk changes?

Thinking Exercise

Is adding an allow rule always bad? When could it be necessary?

The Interview Questions They’ll Ask

  1. “What is a neverallow rule?”
  2. “How do you compare policy versions safely?”
  3. “Why are neverallow changes higher risk than allow changes?”
  4. “How would you detect a regression introduced by a new module?”

Hints in Layers

Hint 1: Use sesearch -A output

sesearch -A -s httpd_t

Hint 2: Normalize output before diffing

Hint 3: Sort and compare a focused rule set

sesearch -A -s httpd_t -t home_root_t -c dir | sort

Books That Will Help

Topic Book Chapter
Policy language “SELinux Notebook” Policy reference
TE rules “SELinux by Example” Policy chapters

Common Pitfalls & Debugging

Problem: “Too much noise”

  • Why: policy output order changes
  • Fix: sort and normalize rules

Problem: “Diff shows changes from booleans”

  • Why: boolean states differ between environments
  • Fix: capture and compare boolean sets alongside policy

Definition of Done

  • Compares two policies reliably
  • Flags new allow rules and removed constraints
  • Generates a security impact summary

Project 9: Ansible SELinux Hardening Role

  • Main Programming Language: YAML (Ansible)
  • Alternative Programming Languages: Python
  • Coolness Level: Level 3
  • Business Potential: 3. The “Enterprise Role”
  • Difficulty: Level 2: Intermediate
  • Knowledge Area: Automation and Compliance
  • Software or Tool: Ansible, semanage, setsebool
  • Main Book: “The Linux Programming Interface”

What you’ll build: An Ansible role that enforces SELinux mode, booleans, and file contexts across a fleet.

Why it teaches SELinux: Real SELinux mastery includes automation and repeatability.

Core challenges you’ll face:

  • Idempotent SELinux changes
  • Audit-friendly configuration

Real World Outcome

$ ansible-playbook selinux_hardening.yml

ok: [web-prod-01] => SELinux enforcing
ok: [web-prod-01] => httpd_can_network_connect: on
ok: [web-prod-01] => /srv/www labeled httpd_sys_content_t

$ ansible web-prod-01 -m command -a "sestatus | head -3"
SELinux status:                 enabled
Current mode:                   enforcing
Loaded policy name:             targeted

The Core Question You’re Answering

“How do I enforce consistent SELinux policy across hundreds of hosts?”

Concepts You Must Understand First

  1. SELinux modes
    • What is the difference between enforcing, permissive, and disabled?
    • How do you persist mode changes in config?
    • Book Reference: SELinux System Administration, modes chapter
  2. Booleans
    • How do you set persistent booleans at scale?
    • Book Reference: Red Hat SELinux Guide, booleans section
  3. File context management
    • How do you define persistent labels for nonstandard paths?
    • Book Reference: SELinux Notebook, labeling section

Questions to Guide Your Design

  1. How do you ensure booleans persist?
  2. How do you avoid breaking existing services?

Thinking Exercise

If a host is in permissive mode but should be enforcing, how do you safely transition?

The Interview Questions They’ll Ask

  1. “What is idempotency in SELinux automation?”
  2. “How do you validate SELinux state across a fleet?”
  3. “How would you roll back a risky SELinux change?”
  4. “What is the safest path to move from permissive to enforcing?”

Hints in Layers

Hint 1: Use Ansible’s selinux module

Hint 2: Use seboolean and sefcontext modules

Hint 3: Add a verification task

- name: Verify SELinux state
  command: sestatus
  register: sestatus_out

Books That Will Help

Topic Book Chapter
Automation “The Linux Programming Interface” System administration sections
SELinux ops “SELinux System Administration” Operations chapters

Common Pitfalls & Debugging

Problem: “Playbook flips to enforcing and breaks services”

  • Why: unlabeled paths or missing booleans
  • Fix: run in permissive first, gather AVCs, then enforce
  • Quick test: ausearch -m avc -ts recent

Problem: “Changes are not persistent”

  • Why: missing -P or missing semanage rules
  • Fix: ensure persistent booleans and fcontext entries
  • Quick test: reboot and verify with getsebool -a

Problem: “Role breaks on reboot”

  • Why: changes not persisted
  • Fix: ensure -P for booleans

Definition of Done

  • Role enforces SELinux mode
  • Role sets booleans and file contexts
  • Role produces audit-friendly report

Project 10: MLS/MCS Classification Demo System

  • Main Programming Language: Python/C
  • Alternative Programming Languages: Rust
  • Coolness Level: Level 5
  • Business Potential: 1. The “Compliance Lab”
  • Difficulty: Level 4: Expert
  • Knowledge Area: MLS/MCS
  • Software or Tool: semanage, custom policies
  • Main Book: “SELinux by Example”

What you’ll build: A demo system that enforces classification rules (no read up, no write down) across labeled documents.

Why it teaches SELinux: MLS/MCS is the theoretical core of mandatory access control.

Core challenges you’ll face:

  • Defining MLS categories
  • Testing enforcement rules

Real World Outcome

$ mls-demo read --user alice --file secret.txt
Denied: no read up

$ mls-demo write --user bob --file unclassified.txt
Denied: no write down

$ ls -Z secret.txt unclassified.txt
system_u:object_r:secret_t:s1 secret.txt
system_u:object_r:public_t:s0 unclassified.txt

The Core Question You’re Answering

“How does SELinux enforce mandatory classification boundaries?”

Concepts You Must Understand First

  1. MLS levels and dominance
    • What do "no read up" and "no write down" mean in practice?
    • Book Reference: SELinux by Example, MLS chapters
  2. MCS categories
    • How do category sets enforce isolation?
    • Book Reference: SELinux by Example, MCS chapters
  3. SELinux users and roles
    • How do SELinux users map to Linux users in MLS policies?
    • Book Reference: SELinux System Administration, user mapping section

Questions to Guide Your Design

  1. How will you simulate different user clearances?
  2. How will you label files for classification?

Thinking Exercise

If a user has clearance s2, can they write to s0? Why?

The Interview Questions They’ll Ask

  1. “Explain Bell-LaPadula in SELinux terms.”
  2. “What is the difference between MLS and MCS?”
  3. “Why does category mismatch cause denials even when TE allows?”
  4. “How do you test MLS enforcement safely?”

Hints in Layers

Hint 1: Use semanage login to map users

Hint 2: Label files with sensitivity levels

Hint 3: Verify labels with ls -Z and test access

Books That Will Help

Topic Book Chapter
MLS “SELinux by Example” MLS chapters
Mandatory access control “Operating Systems: Three Easy Pieces” Security chapters

Common Pitfalls & Debugging

Problem: “MLS not enforced”

  • Why: system running targeted policy
  • Fix: enable MLS policy

Problem: “Users can still read across levels”

  • Why: wrong user mapping or role constraints
  • Fix: verify semanage login -l and role transitions

Definition of Done

  • MLS/MCS labels applied
  • Demonstrates read/write constraints
  • Includes tests for classification rules

Project 11: SELinux Kernel Module Inspector

  • Main Programming Language: C
  • Alternative Programming Languages: Rust (with kernel bindings)
  • Coolness Level: Level 5
  • Business Potential: 1. The “Kernel Debugger”
  • Difficulty: Level 5: Master
  • Knowledge Area: Kernel / LSM Framework
  • Software or Tool: ftrace, bpftrace, debugfs
  • Main Book: “Linux Kernel Development”

What you’ll build: A kernel-level tracer that observes SELinux hooks and AVC decisions in real time.

Why it teaches SELinux: This is the deepest possible view of SELinux internals.

Core challenges you’ll face:

  • Tracing LSM hooks
  • Visualizing AVC cache behavior

Real World Outcome

$ sudo bpftrace -e 'kprobe:selinux_file_permission { printf("%s %d\n", comm, arg0); }'
httpd 1234
sshd  5678

$ cat /sys/kernel/debug/selinux/avc/cache_stats
lookups  12345
hits     12001
misses     344

The Core Question You’re Answering

“What actually happens inside the kernel when SELinux makes a decision?”

Concepts You Must Understand First

  1. LSM hooks
    • Which hooks are invoked for file and socket access?
    • Book Reference: Linux Kernel Development, security chapters
  2. AVC cache
    • How does caching affect performance and correctness?
    • Book Reference: SELinux by Example, architecture chapters
  3. Kernel tracing basics
    • When to use ftrace vs bpftrace vs perf?
    • Book Reference: Linux Kernel Development, tracing sections

Questions to Guide Your Design

  1. Which hooks are most frequent?
  2. How does AVC cache reduce overhead?

Thinking Exercise

If you disable AVC cache, what happens to performance?

The Interview Questions They’ll Ask

  1. “Where does SELinux enforce access?”
  2. “What is the AVC cache?”
  3. “How do you trace SELinux decisions without destabilizing the system?”
  4. “What is the difference between an LSM hook and a syscall?”

Hints in Layers

Hint 1: Start with ftrace

Hint 2: Use bpftrace kprobes

Hint 3: Filter by process to reduce noise

bpftrace -e 'kprobe:selinux_file_permission /comm == "httpd"/ { printf("%s\\n", comm); }'

Books That Will Help

Topic Book Chapter
Kernel security “Linux Kernel Development” Security chapters
SELinux internals “SELinux by Example” Architecture chapters

Common Pitfalls & Debugging

Problem: “System unstable”

  • Why: tracing too many hooks
  • Fix: filter by process or hook type

Problem: “No events captured”

  • Why: kprobes disabled or missing privileges
  • Fix: run as root and verify kernel supports tracing

Definition of Done

  • Traces LSM hooks in real time
  • Reports AVC cache stats
  • Visualizes decision flow

Project 12: Enterprise SELinux Security Platform

  • Main Programming Language: Python/Go
  • Alternative Programming Languages: Rust
  • Coolness Level: Level 5
  • Business Potential: 4. The “Open Core” Infrastructure
  • Difficulty: Level 4: Expert
  • Knowledge Area: Enterprise Security / Full-Stack SELinux
  • Software or Tool: Kafka/Redis/ELK or Loki
  • Main Book: “Clean Architecture” by Robert C. Martin

What you’ll build: A centralized SELinux platform for fleet-wide monitoring, policy change audits, and automated remediation.

Why it teaches SELinux: This capstone integrates every concept into a production-ready system.

Core challenges you’ll face:

  • Distributed log collection
  • Policy compliance tracking
  • Actionable remediation suggestions

Real World Outcome

SELinux Fleet Dashboard
- Enforcing: 120
- Permissive: 4
- Disabled: 1

Top Denials:
1. httpd_t -> user_home_t (read) [Fix: enable httpd_enable_homedirs]
2. myapp_t -> var_log_t (write) [Fix: label logs]
$ selinux-platform-cli analyze --host web-prod-03
Mode: Permissive (WARNING)
Policy: targeted (version 31)

Top Denials (last 1h):
  httpd_t -> user_home_t:file { read }  (156)
  httpd_t -> http_port_t:tcp_socket { name_connect } (47)

The Core Question You’re Answering

“How do I operationalize SELinux security at scale?”

Concepts You Must Understand First

  1. SELinux telemetry fundamentals
    • What fields from AVC logs are required for normalization?
    • Book Reference: SELinux System Administration, troubleshooting chapters
  2. Distributed logging pipelines
    • How do you ingest, buffer, and query log streams at scale?
    • Book Reference: Fundamentals of Software Architecture, observability sections
  3. Policy compliance and change control
    • How do you detect policy drift and unauthorized changes?
    • Book Reference: Foundations of Information Security, governance sections

Questions to Guide Your Design

  1. How do you normalize AVCs across hosts?
  2. How do you avoid false positives?

Thinking Exercise

What metrics indicate SELinux health in production?

The Interview Questions They’ll Ask

  1. “How would you scale SELinux monitoring to 1000 hosts?”
  2. “What are the key SELinux KPIs?”
  3. “How do you detect and remediate permissive or disabled hosts?”
  4. “How do you reduce false positives while preserving security signal?”

Hints in Layers

Hint 1: Start with log collection

Hint 2: Build normalization pipeline

Hint 3: Add policy/boolean snapshots to every host report

Books That Will Help

Topic Book Chapter
Architecture “Clean Architecture” Architecture chapters
Systems ops “The Pragmatic Programmer” Ops sections

Common Pitfalls & Debugging

Problem: “Too many alerts”

  • Why: noisy denials
  • Fix: categorize by root cause and use dontaudit carefully

Problem: “Inconsistent data across distros”

  • Why: policy versions differ and messages vary slightly
  • Fix: normalize by policy version and use schema mapping

Problem: “MCS categories explode cardinality”

  • Why: each category combination looks like a unique tenant
  • Fix: aggregate by domain and category range, not exact label

Definition of Done

  • Collects AVCs from multiple hosts
  • Generates remediation suggestions
  • Tracks SELinux mode and policy changes
  • Provides compliance summary