Introduction
Android’s robust security model relies heavily on a multi-layered approach, with SELinux (Security-Enhanced Linux) serving as a critical component for Mandatory Access Control (MAC). While features like Verified Boot and dm-verity protect the system at boot time by ensuring partition integrity, runtime tampering attempts – especially by sophisticated malware or rootkits – often target active system processes or configurations. This article provides an expert-level guide on leveraging custom SELinux policies to proactively monitor and alert on unauthorized modifications to critical Android system partitions and files, thereby significantly enhancing the device’s integrity monitoring capabilities.
Understanding Android System Integrity and SELinux
Android system integrity is foundational to device security. Verified Boot, through cryptographically signing boot images and partitions, ensures that the operating system loaded is the one intended by the device manufacturer. dm-verity extends this by creating a Merkle tree hash structure over read-only partitions (like /system, /vendor, /product), ensuring their integrity continuously during runtime. If a block is altered, dm-verity detects the change, preventing its use and potentially triggering a verified boot failure.
However, dm-verity primarily focuses on detecting alterations to read-only partitions. What about subtle runtime manipulations of critical system services, configuration files, or user-space binaries located in potentially writable areas, or even attempts to modify immutable partitions that indicate a deeper compromise? This is where SELinux plays a vital role. SELinux enforces fine-grained access control on all processes, files, and IPC mechanisms, dictating precisely what each component is allowed to do. By customizing SELinux policies, we can explicitly define and audit unexpected behaviors, even if they are ultimately denied by other mechanisms (like file permissions or dm-verity).
SELinux Basics for Integrity Monitoring
SELinux operates on the principle of least privilege, where every action must be explicitly permitted. Key concepts include:
- Contexts: Labels applied to all files, processes, and other system objects, e.g.,
u:object_r:system_file:s0. - Types: The most granular component of a context, defining the role of an object (e.g.,
system_file). - Domains: Types assigned to processes, defining their permissions.
- Rules: Policies written in SELinux policy language (
.tefiles) that define allowed interactions between domains and types. - Audit Rules: Special rules (e.g.,
auditallow) that log attempts, even if they are denied by other policies or lower-level access controls.
By defining specific types for critical system assets and writing audit rules, we can ensure that any attempt to modify these assets is logged, providing invaluable forensic data and real-time alerts.
The Challenge: Detecting Covert Runtime Tampering
While dm-verity makes it extremely difficult to persistently modify /system, a sophisticated attacker might attempt to:
- Gain temporary write access to a normally read-only partition (e.g., via kernel exploit).
- Modify critical configuration files in writable partitions (e.g.,
/data/local,/data/misc) that impact system behavior. - Tamper with SELinux policies themselves (a very high-privilege attack).
Our goal is to configure SELinux to generate an alert whenever a specific, unauthorized write or modification attempt occurs on designated critical system resources, regardless of whether the attempt ultimately succeeds due to other protective layers.
Crafting Custom SELinux Policies for Integrity Monitoring
The core idea is to define a new SELinux type for the files we want to monitor for integrity, and then implement an auditallow rule that logs any write attempt to those files. This ensures that even if dm-verity or file permissions prevent the write, the attempt itself is recorded in the kernel logs (dmesg).
Step-by-Step Implementation
1. Prerequisites
- An Android Open Source Project (AOSP) build environment.
- Familiarity with building Android from source.
- A device capable of flashing custom
boot.imgorvendor_boot.img.
2. Define a New SELinux File Type
We’ll create a new SELinux type to specifically label our critical, immutable system configuration files. Navigate to your AOSP source tree and locate the SELinux policy definitions. A good place to add a new file type is often in a device-specific policy directory (e.g., device/<vendor>/<device>/sepolicy/) or directly within system/sepolicy/public/file.te if you are modifying AOSP core.
Create or modify a .te (type enforcement) file, for example, my_integrity.te:
# my_integrity.te
type system_immutable_config_t;
file_type_core(system_immutable_config_t);
This defines system_immutable_config_t as a core file type.
3. Map Critical Files to the New Type
Next, we need to assign this new type to the specific files we want to monitor. Critical files often include /system/build.prop, /system/etc/security/mac_permissions.xml, or other sensitive configuration files. These are typically read-only, but monitoring write attempts is key.
Edit the file_contexts file in your device’s policy directory (e.g., device/<vendor>/<device>/sepolicy/private/file_contexts or system/sepolicy/private/file_contexts). Add entries for the files you want to monitor:
# file_contexts additions
/system/build.prop u:object_r:system_immutable_config_t:s0
/system/etc/security/mac_permissions.xml u:object_r:system_immutable_config_t:s0
The backslash before the dot (.) is important for regex matching in file_contexts.
4. Implement the Audit Rule
To generate alerts, we’ll use an auditallow rule. This rule tells SELinux to log any specified access attempt, regardless of whether it’s ultimately permitted or denied. Add this rule to an appropriate .te file, such as a device-specific policy or system/sepolicy/private/audit.te:
# audit.te or my_integrity.te additions
# Audit any attempt by any domain to write to system_immutable_config_t files.
auditallow domain system_immutable_config_t:file { write create setattr append unlink rename link };
Here, domain is a wildcard representing any process domain. This rule means that if *any* process tries to perform a write-related operation (write, create, set attributes, append, unlink, rename, link) on a file labeled system_immutable_config_t, SELinux will log an AVC (Access Vector Cache) event with a
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 →