linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Simulator
  • Knowledge base
  • Interview prep
Index
Categories
All entries
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
home/linux/kb/Security/selinux-policy

kb/security ── Security ── advanced

SELinux policy: types, domains, audit2allow

SELinux: every process has a domain, every object has a type. The policy defines which domains may do what to which types. audit2allow generates rules from AVC denials, semanage tunes, and .pp files are policy modules.

view as markdownaka: selinux-types, selinux-modules, semanage, selinux-targeted, selinux-mls

Why go deeper than selinux-apparmor

The basic overview of Mandatory Access Control is in selinux-apparmor. This article covers policy mechanics: how to write, debug, and extend rules, and how to work with booleans, file contexts, and port labelling.

Real scenarios:

  • "Apache cannot read /var/www/data/" -> fix the file context
  • "Custom service on a nonstandard port -> SELinux blocks the bind" -> port label
  • "You need a legitimate exception, not a disable" -> custom policy module
  • "Mass tuning via switches" -> SELinux booleans
  • "Compliance", fine-grained control with auditing

Type enforcement, the foundation

SELinux has a four-part security context:

user_u:role_r:type_t:level
└── user (SELinux user, not the Linux user!)
      └── role (system_r, unconfined_r, ...)
            └── type / domain (httpd_t, sshd_t, var_log_t, ...)
                  └── MLS/MCS level (s0, s0:c1.c5, ...)
  • On a process the type is called the domain (httpd_t, sshd_t)
  • On a file, socket, or port it is the type (var_log_t, httpd_sys_content_t)
  • A type enforcement rule: allow source_domain target_type:class { permissions };

Example:

allow httpd_t httpd_sys_content_t:file { read getattr open };

This means a process in the httpd_t domain may read/getattr/open files of type httpd_sys_content_t. Everything else is denied.

View a context:

bash
ls -Z /var/www/html/                       # files
ps -eZ | grep httpd                         # processes
ss -tnpZ                                    # sockets
id -Z                                       # current user context

Targeted vs MLS vs MCS

PolicyWhat
targeteddefault; confines services only (httpd, sshd, named...). Users in unconfined_t run unrestricted
mlsMulti-Level Security; for government, high-grade systems with classification levels
mcsMulti-Category Security; containers in OpenShift get different categories for isolation

Active mode:

bash
sestatus
# SELinux status:                 enabled
# Loaded policy name:             targeted
# Current mode:                   enforcing
# Mode from config file:          enforcing
  • enforcing blocks and logs
  • permissive only logs, does not block (for debugging)
  • disabled is off, labels are not maintained (to come back you must relabel)

audit2allow, generating rules from denials

The main workflow when "X does not work because of SELinux":

bash
# 1. Enable permissive temporarily (for a specific domain) or fully
semanage permissive -a httpd_t              # for one domain
# OR
setenforce 0                                 # globally, for debugging
# 2. Reproduce the problem
systemctl restart httpd
curl http://localhost/
# 3. Find denials in auditd
ausearch -m AVC -ts recent
# 4. Generate a policy rule
ausearch -m AVC -ts recent | audit2allow -M my-httpd-fix
# Creates my-httpd-fix.te (text) and my-httpd-fix.pp (binary)
# 5. Load it
semodule -i my-httpd-fix.pp
# 6. Return to enforcing
semanage permissive -d httpd_t
setenforce 1

audit2allow is not "the right way". It is a quick patch. First check whether the context you need already exists, or whether there is a boolean.

Booleans, targeted switches

The distribution policy includes dozens of booleans for common on/off features:

bash
# Show all
getsebool -a | head
# A specific one
getsebool httpd_can_network_connect
# -> off
# Enable temporarily (until reboot)
setsebool httpd_can_network_connect on
# Enable permanently
setsebool -P httpd_can_network_connect on
# Description
semanage boolean -l | grep httpd

Common ones:

  • httpd_can_network_connect, apache may reach the network (proxy/upstream)
  • httpd_can_sendmail
  • samba_export_all_rw
  • nfs_export_all_rw
  • ssh_chroot_rw_homedirs

Before audit2allow, always check for a boolean. There is most likely a ready-made solution already.

File contexts, semanage fcontext

A file's context is an xattr named security.selinux (see extended-attributes). When a file is created, it inherits the context from the parent directory.

If you put a file in a nonstandard location, its context will be wrong:

bash
ls -Z /opt/myapp/index.html
# unconfined_u:object_r:usr_t:s0 ...
# Apache wants httpd_sys_content_t. Assign it:
semanage fcontext -a -t httpd_sys_content_t '/opt/myapp(/.*)?'
restorecon -Rv /opt/myapp
  • semanage fcontext adds a rule to the database (persistent)
  • restorecon applies the rules to existing files
  • chcon changes the context without writing to the database (temporary, will not survive a relabel)

List the current ones:

bash
semanage fcontext -l | grep httpd

Port labels

SELinux labels sockets too:

bash
# apache wants port 8080
systemctl restart httpd                     # FAIL: SELinux denied
ausearch -m AVC | tail -5                   # you will see a denial on name_bind
# Fix:
semanage port -a -t http_port_t -p tcp 8080
systemctl restart httpd                     # OK
# List
semanage port -l | grep http

If sshd runs on a nonstandard port, do the same:

bash
semanage port -a -t ssh_port_t -p tcp 2222

Custom policy module

When you need a legitimate exception, package it as a module:

te
# my-custom.te
module my-custom 1.0;
require {
    type httpd_t;
    type custom_data_t;
    class file { read getattr open };
}
allow httpd_t custom_data_t:file { read getattr open };

Compile and install:

bash
checkmodule -M -m -o my-custom.mod my-custom.te
semodule_package -o my-custom.pp -m my-custom.mod
semodule -i my-custom.pp

View loaded modules:

bash
semodule -l | head

Remove:

bash
semodule -r my-custom

Relabel the whole filesystem

After a catastrophic misconfiguration or after bringing SELinux back from disabled:

bash
# On the next boot
touch /.autorelabel
reboot
# Or interactively
fixfiles -F restore

This can take hours on large filesystems.

sealert, graphical AVC analyzer

bash
dnf install setroubleshoot setroubleshoot-server
systemctl enable --now setroubleshootd

It analyzes an AVC denial and suggests a fix in plain language:

bash
sealert -a /var/log/audit/audit.log

This produces "Try changing boolean X" / "Try restorecon" / "If you really need this, generate a module".

Useful for juniors and people new to SELinux.

When things go wrong

  • "SELinux is preventing..." in the log: run sealert -a /var/log/audit/audit.log or ausearch -m AVC -ts recent | audit2allow.
  • Permission denied with no obvious cause: check ls -Z and getenforce. The problem is often not in Linux permissions but in the SELinux context.
  • Correct mode 644, owner, group, but the read fails: the context does not fit the domain. Run restorecon -Rv path.
  • semanage not found: install policycoreutils-python-utils (RHEL) or policycoreutils-python (on older systems).
  • dontaudit rules hide denials: some denials are suppressed by the system. semodule -DB disables dontaudit for debugging. Remember to revert: semodule -B.
  • A policy module stops working after a restart: the module is not loaded into the active policy. Check semodule -l | grep my-custom. If it is missing, run semodule -i again.
  • Changes made with chcon are lost: that is expected. chcon does not write to the database. Use semanage fcontext plus restorecon.

Checklist "SELinux problem"

  1. getenforce, the mode. If Permissive, the problem is not in SELinux.
  2. ausearch -m AVC -ts recent, is there a denial in audit.log
  3. ls -Z, what context the unreadable file has
  4. ps -eZ | grep procname, what domain the process runs in
  5. semanage boolean -l | grep <topic>, is there a ready-made toggle
  6. semanage fcontext -l | grep <path>, what context it should be
  7. restorecon -Rv, fix existing files
  8. audit2allow as a last resort

§ команды

bash
sestatus

Full SELinux status: mode, policy, mountpoint

bash
ls -Z /var/www/html

File contexts, a quick way to see what is labeled how

bash
ps -eZ | grep httpd

Domain of a running process, the first check for AVC debugging

bash
ausearch -m AVC -ts recent | audit2allow -M my-fix

Generate a policy module from recent denials, a quick patch

bash
setsebool -P httpd_can_network_connect on

Enable a boolean permanently, survives a reboot (-P)

bash
semanage fcontext -a -t httpd_sys_content_t '/opt/app(/.*)?' && restorecon -Rv /opt/app

Assign an httpd context to a nonstandard path and apply it

bash
semodule -DB

Disable dontaudit (for debugging); remember to restore with semodule -B

§ см. также

  • selinux-apparmorSELinux and AppArmor: Mandatory Access ControlSELinux and AppArmor are MAC: a control layer on top of normal permissions. They stop a process from doing anything outside its profile or type.
  • auditdauditd: syscall and file auditauditd writes kernel events to /var/log/audit/audit.log: file watches (-w), syscall rules (-a), execs. Use ausearch to search, aureport for reports. This is the basis of compliance (PCI-DSS, HIPAA, FZ-152).
  • capabilitiesLinux capabilities: privilege bitsCapabilities split root's power into 40+ independent bits: NET_ADMIN, SYS_PTRACE, and so on. You can grant a process a slice of that power without making it full root.
  • file-permissionsFile permissions: rwx and chmodEvery file has three permission sets: for the owner, the group, and others. Each set is three bits: read (r), write (w), execute (x). You change them with `chmod`.
  • extended-attributesExtended attributes (xattr): arbitrary file metadataxattr are key-value metadata on an inode beyond stat. 4 namespaces: user (open), trusted (root), system (ACL), security (SELinux, capabilities). getfattr reads, setfattr writes.
  • cis-benchmark-hardeningCIS Benchmark and system hardening (lynis, OpenSCAP)CIS Benchmark is the Linux hardening standard. Lynis is a fast local audit with a score, OpenSCAP is the formal one with XCCDF profiles and a SCAP report. ansible-lockdown remediates. Keep audit and remediate separate.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies