Advanced OS Customizations & Bootloaders

Deep Dive: Understanding Android’s `sepolicy` and `plat_sepolicy` Architecture

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction to Android SELinux and Policy Architecture

Android’s security model relies heavily on SELinux (Security-Enhanced Linux), a Mandatory Access Control (MAC) system that augments the traditional Discretionary Access Control (DAC). Unlike DAC, where access is granted based on user identity, SELinux makes access decisions based on the security context of subjects (processes) and objects (files, sockets, etc.). This ensures that even if a service is compromised, its actions are still constrained by its defined SELinux policy. For developers and custom ROM builders, understanding the `sepolicy` and `plat_sepolicy` architecture is crucial for maintaining device security and ensuring proper functionality.

Initially, Android used a monolithic `sepolicy` that combined all rules for the entire system. However, with the advent of Project Treble, a new separation was introduced, giving rise to `plat_sepolicy` and a more structured approach to policy management.

SELinux Fundamentals in Android

SELinux operates in one of two primary modes: Enforcing or Permissive. In Enforcing mode, any action that violates the policy is denied and logged. In Permissive mode, violations are only logged, not denied, making it useful for debugging new policies.

The core of SELinux in Android revolves around a set of policy files compiled into a single binary called `sepolicy` that resides in the boot partition or `vendor_boot` partition. This binary is loaded by the kernel at boot time.

Key SELinux Concepts:

  • Types: Labels applied to objects (files, devices, properties) and domains (processes). E.g., `init_t`, `system_file`, `app_data_file`.
  • Domains: Special types representing processes. E.g., `untrusted_app_t` for unprivileged apps, `system_server_t` for the system server.
  • Rules: Define allowed interactions. Common rules include `allow`, `dontaudit`, `neverallow`.

A basic `allow` rule looks like this:

allow source_type target_type : class perm_set;

For example, `allow app_t app_data_file:dir { read write add_name };` allows applications to read, write, and create files in their respective data directories.

The Traditional `sepolicy` (Pre-Treble & Base)

Before Project Treble, all SELinux rules, including those for the Android platform, device-specific customizations, and vendor components, were compiled together into a single `sepolicy` file. This made updating the Android framework (system partition) independently from the vendor implementation (vendor partition) extremely challenging, often leading to compatibility issues.

The primary source for this monolithic policy was typically located in `system/sepolicy` within the AOSP source tree. Device manufacturers would then add their specific policies in device trees (e.g., `device/manufacturer/device-name/sepolicy`) to cater to unique hardware and services.

Example Policy Location:

  • AOSP Base: `system/sepolicy/`
  • Device Specific: `device/manufacturer/device_name/sepolicy/`
  • Vendor Specific: `vendor/manufacturer/sepolicy/` (though this was less structured pre-Treble)

Introducing `plat_sepolicy` and Project Treble’s Impact

Project Treble aimed to modularize Android, separating the Android OS framework from the vendor implementation. A key part of this separation involved SELinux policy. `plat_sepolicy` (platform sepolicy) was introduced to define the security policy that is guaranteed to be stable and provided by the Android platform itself, independent of the vendor implementation.

The `plat_sepolicy` lives primarily in `build/make/target/sepolicy/plat_sepolicy_and_mapping`. This directory contains versioned platform policies and a mapping file that dictates which policy version is used for a given Android release. This ensures ABI/API stability between the system and vendor partitions by maintaining a consistent SELinux interface.

The Role of `plat_sepolicy`:

  1. Platform Stability: Defines the core SELinux types and rules that Android itself requires, providing a stable interface for vendor implementations.
  2. Versioned Policy: `plat_sepolicy` is versioned (e.g., `plat_sepolicy.cil`, `plat_sepolicy_29.cil`, `plat_sepolicy_30.cil`), allowing older vendor images to run with newer Android frameworks, provided their policy is compatible with the framework’s `plat_sepolicy` version.
  3. System-Vendor Separation: It strictly limits what vendor processes can interact with platform services and vice-versa, enhancing security and facilitating independent updates.

Custom vendor policies (e.g., for camera HALs, sensors, unique hardware) are expected to extend and adhere to the interfaces defined by `plat_sepolicy` without modifying the platform policy directly. These vendor-specific policies are usually placed in `vendor/<manufacturer>/<device>/sepolicy` or similar locations.

The Policy Compilation Process Explained

The build system combines all relevant SELinux policy components to generate the final `sepolicy` binary. This process is orchestrated by various Makefiles, primarily within `build/make/target/sepolicy/`. The key steps involve:

  1. Collecting Policies: The build system gathers `sepolicy` rules from:
    • AOSP `system/sepolicy` (base platform rules)
    • `plat_sepolicy` (versioned stable platform rules)
    • `system_ext/sepolicy` (OEM extensions to the system partition)
    • `product/sepolicy` (OEM product-specific rules)
    • `vendor/sepolicy` (device and vendor-specific rules, including HALs)
  2. Policy Merging: These individual policy files (often in `.te` format for Type Enforcement) are processed and merged. Conflicts are resolved, and conditional policies are applied.
  3. CIL Conversion: The merged policy is converted into Common Intermediate Language (CIL), which is a more machine-readable format.
  4. Binary Compilation: Finally, the CIL policy is compiled into a binary `sepolicy` file. This binary is typically included in the boot image (`boot.img`) or a separate vendor boot image (`vendor_boot.img`) for devices supporting Generic System Images (GSI) and Project Treble.

Example Build System Reference:

# In build/make/target/sepolicy/sepolicy.mk and treble_sepolicy.mk, you'll find logic like:TARGET_SEPOLICY_DIRS := 	reble_sepolicy uild/make/target/sepolicy/plat_sepolicy_and_mapping uild/make/target/sepolicy rameworks/native/sepolicy/public rameworks/native/sepolicy/private rameworks/native/sepolicy/app rameworks/native/sepolicy/test ...$(foreach d,$(BOARD_SEPOLICY_DIRS), 	reble_sepolicy)

Developing and Debugging SELinux Policies

When developing new features or bringing up new hardware, you will inevitably encounter SELinux denials. These denials are crucial for identifying missing policy rules.

Steps to Debug Denials:

  1. Identify Denials: Use `adb logcat` or `dmesg` to find AVC (Access Vector Cache) denial messages. Look for `avc: denied` strings. Example:
    $ adb shell dmesg | grep

    Android Mobile Specs & Compare Directory

    Are you researching mobile hardware properties, processor SoCs, GPU chipsets, or RAM configurations? Access our complete specs catalog to compare up to 5 devices side-by-side!

    Compare Devices Specs →
Google AdSense Inline Placement - Content Footer banner