← Back to Blogs

SELinux Policies in Android

How Android enforces mandatory access control

1 min read

Android uses SELinux (Security-Enhanced Linux) to enforce mandatory access control (MAC). Unlike traditional Linux permissions where root can do anything, SELinux adds a second layer - even the root user is restricted unless the policy explicitly allows an action. This dramatically limits what a compromised process can do.

DAC vs MAC

SELinux Core Concepts

SELinux Label + Policy Check

  Process: adbd                  File: /data/local/tmp
  Label: u:r:adbd:s0             Label: u:object_r:shell_data_file:s0
         │                              │
         └──────────────┬───────────────┘
                        ▼
           SELinux Policy Check
           'allow adbd shell_data_file:file { read write }'
                        │
             ┌──────────┴──────────┐
             │ ALLOWED             │ DENIED + audit log
             └─────────────────────┘

How Policies are Written

SELinux policies in AOSP are written in .te (type enforcement) files inside system/sepolicy/ (for core AOSP) and device/vendor/ (for vendor-specific policies). Each rule is an 'allow' statement.

Policy Rule Syntax

  allow  <source_type>  <target_type>:<class>  { <permissions> };

  Examples:
  allow  cameraserver  camera_device:chr_file  { read write ioctl };
  #      ↑             ↑               ↑        ↑
  #      process type  file label      file     allowed
  #                                    class    operations

  allow  system_server  app_data_file:dir  { search getattr };
  neverallow untrusted_app  kernel:process  { ptrace };

Enforcing vs Permissive Mode

Working with SELinux Denials

Tip: When your new HAL or daemon is being denied, run in permissive mode first, collect all avc denials, then write the minimal policy that allows exactly what you need. Never write 'allow myprocess domain:file *;' - always be specific.