Introduction to SELinux on Android
Android’s security architecture relies heavily on SELinux (Security-Enhanced Linux), a mandatory access control (MAC) system that augments traditional discretionary access control (DAC). While DAC allows a user to control access to their own resources, MAC enforces a system-wide security policy, preventing even privileged processes from performing unauthorized actions. On Android, SELinux policies define what each process (identified by its security context or ‘domain’) can access (files, devices, IPC, etc.), based on the resource’s security context (‘type’). This powerful mechanism isolates applications and system services, forming a critical part of the sandbox. However, misconfigured SELinux policies can introduce vulnerabilities, leading to sandbox escapes and privilege escalation.
SELinux Fundamentals: Contexts, Domains, and Rules
Understanding SELinux requires grasping a few core concepts:
- Security Contexts: Every process, file, or IPC object on an SELinux-enabled system has an associated security context, typically in the format
user:role:type:sensitivity(e.g.,u:r:untrusted_app:s0for an untrusted application). - Domains: For processes, the ‘type’ component of the security context is often referred to as a ‘domain’. Processes running in specific domains are restricted by rules defined for that domain.
- Types: For files and other objects, the ‘type’ component dictates how processes can interact with them.
- Policy Rules: These define what operations (permissions) a source domain/type can perform on a target domain/type/class. The most common rule is
allow source_type target_type:class permissions;
Android’s SELinux policy is compiled into a binary file (sepolicy) located in the boot or vendor boot partition. When the system boots, this policy is loaded by the kernel. Administrators can query current contexts using ls -Z for files and ps -Z for processes.
adb shell ls -Z /data/data/com.example.app/adb shell ps -Z | grep untrusted_app
Identifying Policy Misconfigurations
Policy misconfigurations often stem from overly permissive rules, incorrect type transitions, or mislabeled resources. Attackers seek out these flaws to elevate privileges or access restricted data.
1. Overly Permissive allow Rules
This is the most direct form of misconfiguration. A domain might be granted permissions to resources it doesn’t legitimately need. For example, an untrusted_app domain should generally not have direct write access to system configuration files.
# Example of a dangerous allow rule (conceptual)allow untrusted_app system_file:file { write execute };
To find such rules, you need access to the device’s compiled sepolicy. First, extract the policy:
# Pull boot.img/vendor_boot.img (method varies by device)adb pull /dev/block/by-name/boot boot.img# Use a tool like AOSP's sepolicy-decompile or libsepol to decompile.sepolicy-decompile boot.img -o my_sepolicy# Then search the decompiled policy for relevant rulesgrep -r "allow untrusted_app" my_sepolicy/
Or use sesearch from AOSP, which allows direct querying of the binary policy:
# Assuming you have adb shell access to a rooted device with sesearchsesearch -s untrusted_app -t system_file -c file -p write
2. Insecure Type Transitions
Type transitions allow a process to change its security context (domain) when it performs certain actions, like creating a file or executing a program. A misconfigured type_transition rule can allow a less privileged domain to transition into a more privileged one, effectively escalating privileges.
# Example of a dangerous type_transition (conceptual)type_transition untrusted_app app_data_file:process app_privileged_domain;
This rule would mean that when an untrusted_app creates a process from an app_data_file, the new process runs in app_privileged_domain, granting it potentially unwanted permissions. You can find these rules using:
sesearch -T -s untrusted_app
3. Mislabeled Resources (File Contexts)
Files, directories, and even device nodes can have incorrect security contexts. If a sensitive file is labeled with a context that an unprivileged domain can access (e.g., read/write), it creates an attack vector. For example, if a system configuration file intended only for system_server is incorrectly labeled as app_data_file, an untrusted application might exploit it.
# Check file contextadb shell ls -Z /data/system/users/0/settings_secure.xml# Check if untrusted_app can write to this file type (if mislabeled)sesearch -s untrusted_app -t settings_file_type -c file -p write
Exploitation Scenarios and Techniques
Once a policy misconfiguration is identified, an attacker needs to leverage it. Here are common exploitation paths:
Scenario 1: Leveraging Overly Permissive Device Node Access
Consider a hypothetical scenario where an untrusted_app domain is mistakenly granted write access to a sensitive kernel device node, such as /dev/kmem or a custom driver interface that controls critical system behavior.
# Identified misconfiguration:allow untrusted_app kernel_mem_device:chr_file { read write };# Exploitation within a compromised app:import android.util.Log;import java.io.FileOutputStream;import java.io.IOException;public class Exploit { public static void main(String[] args) { String devicePath = "/dev/kmem"; // Hypothetical sensitive device try (FileOutputStream fos = new FileOutputStream(devicePath)) { // Attempt to write arbitrary data to kernel memory // This would likely crash the system or allow for code injection byte[] exploitData = new byte[1024]; // Malicious payload // Fill exploitData with carefully crafted shellcode or data fos.write(exploitData); Log.e("SELinux_Exploit", "Successfully wrote to " + devicePath); } catch (IOException e) { Log.e("SELinux_Exploit", "Failed to write to " + devicePath + ": " + e.getMessage()); } }}
This Java code, running within a compromised app’s context, would attempt to write to the device. If the SELinux policy allows it, arbitrary kernel memory writes could lead to full system compromise.
Scenario 2: Abusing Type Transition to Access a Privileged Service
Imagine a system service (e.g., system_server) that, under certain conditions, launches a helper process. If a misconfigured type_transition allows an `untrusted_app` to trigger the creation of this helper process in a privileged domain (e.g., system_app_privileged_domain) simply by creating a file with a specific label, an attacker can gain control.
# Policy rule in sepolicy.conf:type_transition untrusted_app app_data_file:process system_app_privileged_domain;
An attacker could craft a malicious executable, place it in a location with the app_data_file context (if possible), and then trigger the system service to execute it. The new process would inherit system_app_privileged_domain and its associated permissions.
Scenario 3: Leveraging Incorrect File Contexts for Data Exfiltration/Modification
If a sensitive file, like a credential store (e.g., /data/misc/credentials/token.bin), is incorrectly labeled with a generic type (e.g., app_data_file) that untrusted_app can read, the attacker can directly access the data.
# Identified misconfiguration:allow untrusted_app app_data_file:file { read };# In a compromised untrusted_app:import java.io.BufferedReader;import java.io.FileReader;import java.io.IOException;public class DataExfiltrator { public static void main(String[] args) { String sensitiveFile = "/data/misc/credentials/token.bin"; // Hypothetical path try (BufferedReader br = new BufferedReader(new FileReader(sensitiveFile))) { String line; StringBuilder data = new StringBuilder(); while ((line = br.readLine()) != null) { data.append(line).append("n"); } Log.i("SELinux_Exploit", "Sensitive data: " + data.toString()); // Send data to attacker-controlled server } catch (IOException e) { Log.e("SELinux_Exfiltrator", "Failed to read " + sensitiveFile + ": " + e.getMessage()); } }}
Mitigation and Best Practices
Preventing SELinux policy misconfigurations requires a rigorous approach:
- Principle of Least Privilege: Grant only the absolute minimum permissions necessary for each domain and type. Regularly review policies to remove superfluous rules.
- Automated Policy Analysis Tools: Integrate tools like
sesearch,audit2allow(used carefully), and static policy analyzers into the CI/CD pipeline to identify potential over-privileges early. - Thorough Testing: Test new policies extensively in permissive mode to identify all necessary permissions, then transition to enforcing. Monitor
logcatfor SELinux denials. - Avoid Over-Reliance on
dontaudit: While useful during development,dontauditrules should be used sparingly in production as they can mask legitimate security issues. - Regular Policy Audits: Periodically review the entire SELinux policy, especially after system updates or adding new features, to ensure no new misconfigurations have been introduced.
By meticulously crafting and auditing SELinux policies, Android system integrators can significantly enhance the platform’s security posture and prevent sophisticated sandbox escape attempts.
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 →