Home CS Fundamentals OS Security Hardening: SELinux, AppArmor, and seccomp Explained
Advanced 3 min · July 13, 2026

OS Security Hardening: SELinux, AppArmor, and seccomp Explained

Learn how SELinux, AppArmor, and seccomp enforce mandatory access control and sandboxing in Linux.

N
Naren Founder & Principal Engineer

20+ years shipping production systems from the metal up. Written from production experience, not tutorials.

Follow
Production
production tested
July 13, 2026
last updated
2,165
articles · all by Naren
Before you start⏱ 20-25 min read
  • Basic Linux command-line skills
  • Understanding of file permissions and processes
  • Familiarity with Docker (for seccomp examples)
 ● Production Incident 🔎 Debug Guide ⚙ Triage Commands
Quick Answer
  • SELinux, AppArmor, and seccomp are Linux security modules that restrict processes beyond traditional Unix permissions.
  • SELinux uses a security policy with labels and rules for fine-grained control; AppArmor uses path-based profiles.
  • seccomp limits system calls a process can make, reducing kernel attack surface.
  • These tools prevent privilege escalation and contain breaches even if an application is compromised.
  • They are critical for container security (Docker, Kubernetes) and multi-tenant environments.
✦ Definition~90s read
What is Operating System Security?

SELinux, AppArmor, and seccomp are Linux security modules that enforce mandatory access control and system call filtering to confine processes and limit damage from exploits.

Imagine a building with a security guard (traditional permissions) who checks IDs at the entrance.
Plain-English First

Imagine a building with a security guard (traditional permissions) who checks IDs at the entrance. SELinux and AppArmor are like additional guards inside each room who check a detailed badge (security context) before allowing any action. seccomp is like a list of allowed tools a worker can use—if they try to use a banned tool, the guard stops them. Together, they ensure that even if an intruder gets past the front door, they can't roam freely or use dangerous tools.

In the world of Linux security, traditional Unix permissions (read, write, execute) are like a single lock on the front door. Once a user or process is authenticated, they can access almost any resource within their user ID's scope. But what if a vulnerability allows an attacker to execute code as a legitimate user? That's where Mandatory Access Control (MAC) systems like SELinux and AppArmor come in. They enforce security policies that restrict what processes can do, regardless of the user's identity. Additionally, seccomp (secure computing mode) limits the system calls a process can make, drastically reducing the kernel attack surface. These three tools are the backbone of modern Linux security, used in everything from Android to cloud containers. In this tutorial, you'll learn how they work, how to configure them, and how to debug issues when they block legitimate operations. We'll also walk through a real-world production incident where a misconfigured SELinux policy caused a major outage, and how to avoid similar pitfalls.

What is SELinux?

SELinux (Security-Enhanced Linux) is a mandatory access control (MAC) system built into the Linux kernel. It was originally developed by the NSA to enforce the principle of least privilege. Every process and file has a security context (e.g., user:role:type:level). SELinux policies define rules that allow or deny operations based on these contexts. For example, a web server process with type httpd_t can only read files labeled httpd_sys_content_t. Even if the process runs as root, it cannot access files with a different label. This confinement limits damage from exploits. SELinux can run in enforcing mode (deny and log), permissive mode (log only), or disabled. Most Linux distributions (RHEL, Fedora, CentOS) ship with SELinux enabled by default.

selinux_check.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Check SELinux status
sestatus

# List security context of a file
ls -Z /var/www/html/index.html

# Temporarily set SELinux to permissive (for debugging)
sudo setenforce 0

# Restore default context for a file
sudo restorecon -v /var/www/html/index.html

# View recent denials
sudo ausearch -m avc -ts recent
Output
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 33
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html
setenforce: SELinux is disabled
restorecon: reset /var/www/html/index.html context unconfined_u:object_r:user_home_t:s0->unconfined_u:object_r:httpd_sys_content_t:s0
type=AVC msg=audit(1234567890.123:456): avc: denied { read } for pid=1234 comm="httpd" name="index.html" dev=sda1 ino=5678 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file
⚠ Never disable SELinux in production
📊 Production Insight
When copying files from a non-standard location (e.g., a developer's home directory), the SELinux context may be wrong. Always run restorecon after deployment.
🎯 Key Takeaway
SELinux uses security contexts and policies to enforce fine-grained access control beyond traditional Unix permissions.

What is AppArmor?

AppArmor (Application Armor) is another MAC system, but it uses path-based profiles instead of security labels. Each profile defines what files, capabilities, and network access a program can have. For example, a profile for /usr/sbin/nginx might allow read access to /var/www/html/ and write access to /var/log/nginx/. AppArmor is simpler to configure than SELinux and is the default on Ubuntu and Debian. Profiles can be in enforce mode (deny and log) or complain mode (log only). AppArmor is often used in container runtimes like LXD and Docker (via AppArmor profiles).

apparmor_check.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Check AppArmor status
sudo aa-status

# List loaded profiles
sudo aa-status | grep 'profiles are in'

# Set a profile to complain mode
sudo aa-complain /usr/sbin/nginx

# Set a profile to enforce mode
sudo aa-enforce /usr/sbin/nginx

# View AppArmor denials in syslog
grep apparmor /var/log/syslog
Output
apparmor module is loaded.
12 profiles are loaded.
12 profiles are in enforce mode.
/usr/sbin/nginx
...
0 profiles are in complain mode.
...
Setting /usr/sbin/nginx to complain mode.
Setting /usr/sbin/nginx to enforce mode.
Jun 15 10:00:00 host kernel: [12345.678901] audit: type=1400 audit(1234567890.123:456): apparmor="DENIED" operation="open" profile="/usr/sbin/nginx" name="/etc/shadow" pid=1234 comm="nginx" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
💡AppArmor is easier to start with
📊 Production Insight
AppArmor profiles can be bypassed if the program uses hard links or renames files. Ensure profiles cover all paths the program may access.
🎯 Key Takeaway
AppArmor uses path-based profiles to restrict program access, making it simpler than SELinux but less granular.

What is seccomp?

seccomp (secure computing mode) is a Linux kernel feature that restricts the system calls a process can make. It is not a MAC system; it operates at the syscall level. seccomp can be used in two modes: strict mode (only read, write, exit, sigreturn) and filter mode (using BPF to define allowed syscalls). seccomp is commonly used in container runtimes (Docker, runc) to reduce the kernel attack surface. For example, a container might be allowed to call open, read, write, but not mount or reboot. If a process attempts a blocked syscall, it is killed with SIGSYS or the syscall fails with an error. seccomp is essential for sandboxing untrusted code.

seccomp_example.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Check if seccomp is enabled in kernel
cat /proc/sys/kernel/seccomp/actions_avail

# List seccomp filters for a running process (requires root)
sudo cat /proc/1234/status | grep Seccomp

# Example: run a Docker container with a custom seccomp profile
docker run --security-opt seccomp=myprofile.json nginx

# Simple seccomp profile (allow common syscalls)
echo '{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {"names": ["read", "write", "open", "close", "stat", "fstat", "lstat", "poll", "mmap", "munmap", "brk", "rt_sigaction", "rt_sigprocmask", "nanosleep", "clock_gettime", "getpid", "exit", "exit_group"], "action": "SCMP_ACT_ALLOW"}
  ]
}' > myprofile.json
Output
kill_process
kill_thread
trap
allow
Seccomp: 2
(No output from docker run if successful)
🔥seccomp is not a replacement for MAC
📊 Production Insight
Overly restrictive seccomp profiles can break applications. Use strace to identify required syscalls and build a minimal profile.
🎯 Key Takeaway
seccomp limits system calls to reduce kernel attack surface, crucial for container security.

Comparing SELinux, AppArmor, and seccomp

While all three enhance security, they operate at different layers. SELinux and AppArmor are MAC systems that control access to files, capabilities, and inter-process communication. seccomp controls system calls. SELinux uses labels and a centralized policy; AppArmor uses path-based profiles; seccomp uses BPF filters. SELinux is more complex but offers finer granularity (e.g., type enforcement, multi-level security). AppArmor is simpler and easier to manage. seccomp is lightweight and often used in containers. In practice, you might use SELinux or AppArmor for host-level confinement and seccomp for additional syscall filtering in containers.

📊 Production Insight
Mixing SELinux and AppArmor on the same system is not recommended; pick one. seccomp can be used alongside either.
🎯 Key Takeaway
Choose SELinux for fine-grained control, AppArmor for simplicity, and seccomp for syscall filtering. Use them together for layered security.

Practical Configuration Examples

Let's walk through a practical scenario: securing a web server. We'll configure SELinux to allow Apache to read files in /var/www/html and connect to a database. Then we'll create an AppArmor profile for the same. Finally, we'll add a seccomp filter for the Apache process. For SELinux, we need to ensure the file context is httpd_sys_content_t and enable the httpd_can_network_connect boolean. For AppArmor, we create a profile in /etc/apparmor.d/usr.sbin.httpd. For seccomp, we use a Docker container with a custom profile.

configure_web_server.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
# SELinux: allow Apache to connect to network
sudo setsebool -P httpd_can_network_connect on

# Ensure correct context
sudo chcon -t httpd_sys_content_t /var/www/html/index.html

# AppArmor: create a profile for Apache
sudo aa-genprof /usr/sbin/httpd
# Follow prompts to generate profile

# seccomp: run Apache in Docker with custom profile
docker run -d --name web --security-opt seccomp=web_profile.json -p 80:80 httpd
Output
Boolean httpd_can_network_connect set to on
(Interactive aa-genprof session)
(Container runs with seccomp filter)
💡Use booleans for common SELinux adjustments
📊 Production Insight
Always test changes in a staging environment. Use audit2allow to generate custom SELinux policies from denials.
🎯 Key Takeaway
Practical configuration involves setting contexts, booleans, and profiles to match application needs.

Debugging and Troubleshooting

When an application fails due to SELinux, AppArmor, or seccomp, the symptoms often look like permission errors. For SELinux, check /var/log/audit/audit.log with ausearch. Use audit2why to get a human-readable explanation. For AppArmor, check /var/log/syslog or dmesg. Use aa-status to see profile modes. For seccomp, check dmesg for 'seccomp' messages. Temporarily set SELinux to permissive or AppArmor to complain to identify the exact denial. For seccomp, use strace to see which syscall is blocked. Always revert to enforcing/enforce mode after debugging.

debug_security.shBASH
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# SELinux: find denials
sudo ausearch -m avc -ts recent | audit2why

# AppArmor: check denials
sudo grep apparmor /var/log/syslog | tail -20

# seccomp: check kernel messages
sudo dmesg | grep seccomp

# Temporarily disable SELinux (debug only)
sudo setenforce 0
# After debugging, re-enable
sudo setenforce 1

# Temporarily set AppArmor to complain
sudo aa-complain /usr/sbin/httpd
# Re-enforce
sudo aa-enforce /usr/sbin/httpd
Output
type=AVC msg=audit(1234567890.123:456): avc: denied { read } for pid=1234 comm="httpd" name="index.html" dev=sda1 ino=5678 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file
Was caused by:
Missing type enforcement (TE) allow rule.
You can use audit2allow to generate a loadable module to allow this access.
Jun 15 10:00:00 host kernel: [12345.678901] audit: type=1400 audit(1234567890.123:456): apparmor="DENIED" operation="open" profile="/usr/sbin/httpd" name="/etc/shadow" pid=1234 comm="httpd" requested_mask="r" denied_mask="r" fsuid=0 ouid=0
[12345.678901] seccomp: pid 1234 comm "httpd" attempted syscall 59 (execve) - blocked
⚠ Never leave systems in permissive/complain mode
📊 Production Insight
Automate log monitoring with tools like auditd and fail2ban to detect and respond to security denials quickly.
🎯 Key Takeaway
Use audit logs and temporary permissive modes to identify security denials, then create permanent fixes.
● Production incidentPOST-MORTEMseverity: high

The SELinux Policy That Took Down a Web Farm

Symptom
Users saw HTTP 403 Forbidden errors on all web pages; Apache error logs showed 'Permission denied' for /var/www/html/index.html.
Assumption
The developer assumed it was a file ownership issue and changed permissions to 777, but the error persisted.
Root cause
The file /var/www/html/index.html had an incorrect SELinux context (user_home_t instead of httpd_sys_content_t), so SELinux denied Apache access.
Fix
Restored the correct SELinux context using restorecon -v /var/www/html/index.html and verified with ls -Z.
Key lesson
  • Always check SELinux context when files are moved or copied from non-standard locations.
  • Use audit2why and audit2allow to interpret SELinux denials.
  • Set SELinux to permissive mode temporarily for debugging, but never in production.
  • Automate context restoration in deployment scripts.
  • Monitor SELinux audit logs (ausearch) proactively.
Production debug guideSymptom to Action3 entries
Symptom · 01
Application fails with 'Permission denied' despite correct file permissions
Fix
Check SELinux audit logs: ausearch -m avc -ts recent. Use audit2why to get human-readable explanation.
Symptom · 02
AppArmor denies access and logs 'DENIED' messages
Fix
Check /var/log/syslog or dmesg for 'apparmor' entries. Use aa-status to see loaded profiles. Temporarily set profile to complain mode: aa-complain /path/to/profile.
Symptom · 03
seccomp kills process with signal 31 (SIGSYS)
Fix
Check dmesg for 'seccomp' messages. Use strace to identify blocked syscall. Adjust seccomp filter or add allowed syscall.
★ Quick Debug Cheat SheetCommon symptoms and immediate actions for SELinux, AppArmor, and seccomp issues.
SELinux denial (AVC)
Immediate action
Check audit log
Commands
ausearch -m avc -ts recent
audit2why < /var/log/audit/audit.log
Fix now
restorecon -Rv /path
AppArmor denial+
Immediate action
Check syslog
Commands
grep apparmor /var/log/syslog
aa-status
Fix now
aa-complain /path/to/profile (temporary)
seccomp SIGSYS+
Immediate action
Check dmesg
Commands
dmesg | grep seccomp
strace -p <pid>
Fix now
Modify seccomp filter to allow syscall
FeatureSELinuxAppArmorseccomp
TypeMAC (label-based)MAC (path-based)Syscall filtering
GranularityVery fine (types, levels)Moderate (paths, capabilities)Syscall-level
ConfigurationPolicy files, booleansProfiles per programBPF filters
Default onRHEL, Fedora, CentOSUbuntu, DebianEnabled in kernel, no default policy
Learning curveSteepModerateLow
Use caseEnterprise servers, MLSDesktop, simpler environmentsContainers, sandboxes
⚙ Quick Reference
5 commands from this guide
FileCommand / CodePurpose
selinux_check.shsestatusWhat is SELinux?
apparmor_check.shsudo aa-statusWhat is AppArmor?
seccomp_example.shcat /proc/sys/kernel/seccomp/actions_availWhat is seccomp?
configure_web_server.shsudo setsebool -P httpd_can_network_connect onPractical Configuration Examples
debug_security.shsudo ausearch -m avc -ts recent | audit2whyDebugging and Troubleshooting

Key takeaways

1
SELinux and AppArmor enforce mandatory access control beyond traditional permissions.
2
seccomp restricts system calls to reduce kernel attack surface.
3
Use audit logs and temporary permissive modes to debug denials.
4
Never disable these security features in production; instead, tune policies.
5
Combine seccomp with a MAC system for defense in depth.

Common mistakes to avoid

3 patterns
×

Disabling SELinux because it's 'too hard'

×

Setting file permissions to 777 to fix 'Permission denied'

×

Using a too-restrictive seccomp profile that breaks the application

INTERVIEW PREP · PRACTICE MODE

Interview Questions on This Topic

Q01JUNIOR
Explain the difference between DAC and MAC.
Q02SENIOR
How would you troubleshoot a 'Permission denied' error that persists aft...
Q03SENIOR
Describe a scenario where seccomp would prevent a container escape.
Q01 of 03JUNIOR

Explain the difference between DAC and MAC.

ANSWER
DAC (Discretionary Access Control) allows users to control access to their own resources (e.g., file permissions). MAC (Mandatory Access Control) enforces system-wide policies that override user settings. SELinux and AppArmor are MAC systems.
FAQ · 5 QUESTIONS

Frequently Asked Questions

01
Can I use SELinux and AppArmor together?
02
Does seccomp replace SELinux or AppArmor?
03
How do I create a custom SELinux policy?
04
What is the difference between enforcing and permissive mode?
05
How do I check if a process is confined by seccomp?
N
Naren Founder & Principal Engineer

20+ years shipping production systems from the metal up. Written from production experience, not tutorials.

Follow
Verified
production tested
July 13, 2026
last updated
2,165
articles · all by Naren
🔥

That's Operating Systems. Mark it forged?

3 min read · try the examples if you haven't

Previous
Real-Time Operating Systems: FreeRTOS and VxWorks
17 / 17 · Operating Systems
Next
Introduction to Computer Networks