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/Processes & resources/selinux-apparmor

kb/processes ── Processes & resources ── advanced

SELinux and AppArmor: Mandatory Access Control

SELinux and AppArmor are MAC: a control layer on top of normal permissions. They stop a process from doing anything outside its profile or type.

view as markdownaka: selinux, apparmor, lsm, linux-security-modules, mandatory-access-control

DAC vs MAC

  • DAC (Discretionary Access Control) is normal file-permissions, UID/GID/rwx. The owner decides who is allowed what.
  • MAC (Mandatory Access Control) is a system-wide policy that users cannot bypass. This process may write ONLY to these paths and bind ONLY these ports, regardless of what DAC says.

Both run at the same time. To allow something you need both DAC and MAC to allow it. To deny it, one of them is enough.

The implementation is Linux Security Modules (LSM): SELinux, AppArmor, SMACK, TOMOYO, Landlock. A system usually has one active.

SELinux

Common on RHEL/CentOS/Fedora/CoreOS. It works with labels:

  • Each process has a context: user:role:type:level
  • Each file or socket has the same kind of context
  • The policy says this type may do THIS to that type

The most important part is the type (for example, httpd_t for nginx, var_log_t for logs). There are countless rules like httpd_t may write httpd_log_t.

Inspecting

bash
getenforce                          # Enforcing / Permissive / Disabled
sestatus                             # full detail
ls -Z /var/log/messages              # see the SELinux context of a file
ps -eZ | head                        # process contexts
id -Z                                # my context
ausearch -m AVC -ts recent           # recent denials in the audit log

Modes

  • Enforcing: rules apply, violations are blocked
  • Permissive: rules do NOT apply, but violations are logged (for debugging and for building your own profile)
  • Disabled: turned off (requires a reboot)
bash
sudo setenforce 0                    # switch to permissive on the fly
sudo setenforce 1                    # back to enforcing
# Permanently in /etc/selinux/config: SELINUX=enforcing|permissive|disabled

When something breaks

The symptom: the plain chmod 755 is correct, everything checks out, but nginx still cannot read the file. Suspect SELinux:

bash
sudo ausearch -m AVC -ts recent | tail -5
# type=AVC msg=audit(...): avc: denied { read } for pid=1234 comm="nginx"
#   ... scontext=system_u:system_r:httpd_t:s0
#   ... tcontext=unconfined_u:object_r:user_home_t:s0

You can see it: httpd_t is trying to read user_home_t, and that is denied. The fixes:

  • Set the right label: sudo chcon -t httpd_sys_content_t /path/file
  • Permanently: sudo semanage fcontext -a -t httpd_sys_content_t '/path(/.*)?' plus sudo restorecon -Rv /path
  • Build a custom rule (audit2allow):
bash
sudo ausearch -m AVC -ts recent | audit2allow -M mymodule
sudo semodule -i mymodule.pp

AppArmor

Common on Ubuntu/Debian/SUSE. It works with path-based profiles rather than labels. A profile is a file in /etc/apparmor.d/:

/usr/sbin/nginx {
  /etc/nginx/** r,
  /var/log/nginx/* w,
  /var/www/** r,
  network tcp,
  capability net_bind_service,
}

The binary is bound to the profile. Whatever is not allowed is denied.

Inspecting

bash
sudo aa-status                       # summary: loaded profiles and their modes
cat /sys/kernel/security/apparmor/profiles

Modes

  • enforce: blocks
  • complain: logs but does not block (the SELinux permissive equivalent for one profile)
  • disabled
bash
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
sudo aa-disable /etc/apparmor.d/usr.sbin.nginx

Debugging

Denials land in kern.log / the journal:

bash
sudo dmesg | grep apparmor=
sudo journalctl -k | grep DENIED

The aa-genprof <binary> utility runs the program in complain mode, collects its accesses, and turns them into a profile. Handy for writing your own profiles.

SELinux vs AppArmor

SELinuxAppArmor
Approachlabels on every objectpath-based profiles
Granularityvery highmedium
Complexityhighmedium
DefaultRHEL familyUbuntu / SUSE
Reloadsometimes needs an FS relabelhot-reload of profiles

In containers (Docker, podman, k8s) both are used: the profile applies to the container process.

When people turn it off (and why that is a bad idea)

The temptation: it does not work, so turn it off. That removes a whole layer of protection. A better path:

  1. Switch to permissive/complain (logs without blocking)
  2. Work out what exactly is denied
  3. Adjust the policy or the label

Turning it off entirely is reasonable only when you have another isolation system in place (containers plus namespaces plus seccomp plus capabilities).

How it fits the stack

  • MAC (SELinux/AppArmor): what you MAY open, listen on, or write
  • DAC (file-permissions): normal rights
  • capabilities: which root privileges you hold
  • seccomp: which syscalls are allowed

These are four independent layers. Production servers use all four.

§ команды

bash
getenforce

Current SELinux mode (Enforcing/Permissive/Disabled)

bash
sudo aa-status

AppArmor summary: loaded profiles and their modes

bash
ls -Z /var/log/messages

SELinux context of a file (shown after the normal permissions)

bash
sudo ausearch -m AVC -ts recent | audit2allow -M mymod

Generate an SELinux policy module from recent denials

bash
sudo journalctl -k | grep -i 'denied\|apparmor='

Denials in the kernel log, for debugging MAC violations

§ см. также

  • 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`.
  • 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.
  • seccompseccomp: a system call filterseccomp is a kernel-level syscall filter. A process declares "only these are allowed", and the kernel cuts off the rest. It anchors the Docker and Chrome sandbox.
  • kernel-modulesKernel modules: LKM, modprobe, signing, DKMSAn LKM is code loaded into the kernel at runtime. modprobe resolves dependencies through depmod. Sign a module for Secure Boot. DKMS rebuilds out-of-tree modules after a kernel upgrade. Lockdown mode blocks unsigned modules.
  • selinux-policySELinux policy: types, domains, audit2allowSELinux: 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.
  • 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).
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies