Introduction to SELinux on Android
Security-Enhanced Linux (SELinux) is a mandatory access control (MAC) security mechanism that plays a pivotal role in hardening Android devices. Unlike discretionary access control (DAC), where access decisions are made based on user identity, SELinux enforces policies defined by the system administrator, ensuring that applications and services operate with the absolute minimum necessary permissions. This robust security model prevents privilege escalation attacks and contains damage from compromised processes.
The Role of SELinux in Android Security
Android has adopted SELinux since version 4.3 to provide fine-grained control over what processes can access which resources. Every file, directory, and process on an Android system has an SELinux context, or label, associated with it. The SELinux policy, a set of rules loaded into the kernel, dictates interactions between these labeled entities. For instance, a camera application might only be allowed to access camera hardware and save photos to specific directories, preventing it from reading sensitive system files or network interfaces it doesn’t need.
What are AVC Denials?
When a process attempts an action that is not explicitly permitted by the loaded SELinux policy, the kernel’s SELinux module blocks the action and logs an “Access Vector Cache (AVC) denial.” These denials are crucial for identifying policy gaps or security incidents. In “enforcing” mode, which is the default for production Android devices, all unpermitted actions are blocked. In “permissive” mode, actions are logged but not blocked, which is useful for debugging policy issues during development.
Diagnosing SELinux AVC Denials
Troubleshooting AVC denials requires understanding how to extract and interpret the denial messages. These messages provide vital clues about the source and nature of the policy violation.
Gathering Denial Logs
The primary tools for obtaining AVC denial logs on an Android device are adb logcat and dmesg. Ensure your device is connected via USB and ADB debugging is enabled.
To view real-time kernel messages, including AVC denials, use:
adb shell dmesg | grep "avc: denied"
For a broader view that includes Android’s application and system logs, filter logcat output:
adb logcat | grep "avc: denied"
For persistent logging across reboots or when investigating intermittent issues, you might need to capture logs to a file:
adb shell "dmesg | grep 'avc: denied'" > avc_denials.txt
Interpreting AVC Denial Messages
An AVC denial message can look intimidating, but it contains structured information essential for diagnosis. Here’s an example and its breakdown:
type=1400 audit(1678886400.000:123): avc: denied { read } for pid=1234 comm="mydaemon" name="config.txt" dev="mmcblk0p1" ino=5678 scontext=u:r:mydaemon_init:s0 tcontext=u:object_r:system_data_file:s0 tclass=file permissive=0
type=1400 audit(...): Standard audit log header.avc: denied { read }: The specific permission that was denied (e.g., read, write, execute, open).pid=1234 comm="mydaemon": The process ID (PID) and command name of the subject attempting the action. This helps identify the offending application or service.name="config.txt": The name of the file or resource being accessed.scontext=u:r:mydaemon_init:s0: The Security Context of the Subject (the process attempting the action). This identifies the domain of the process.tcontext=u:object_r:system_data_file:s0: The Security Context of the Target (the resource being accessed). This identifies the type of the resource.tclass=file: The Target Class (e.g., file, directory, socket, process).permissive=0: Indicates the device is in enforcing mode (1would mean permissive mode).
From this example, we understand that a process named mydaemon, running in the mydaemon_init SELinux domain, attempted to read a file named config.txt which has a system_data_file context. The policy currently does not allow mydaemon_init to read system_data_file. This gives us a clear path for policy modification.
Developing Custom SELinux Policies
Customizing SELinux policy involves writing or modifying Type Enforcement (TE) files and recompiling the policy. This is typically done within the Android Open Source Project (AOSP) build environment.
Understanding SELinux Policy Structure
Android’s SELinux policy is composed of numerous .te files, each defining rules for specific domains (processes) and types (resources). Key concepts include:
- Domains: Represent processes (e.g.,
system_server,mydaemon). - Types: Represent resources (e.g.,
system_data_file,camera_device). - Rules: Define allowed interactions (e.g.,
allow source_domain target_type:class permission_set;).
These .te files are compiled into a binary sepolicy file, which is then included in the device’s boot image (specifically vendor_boot.img or boot.img depending on Android version and device architecture).
Crafting a New Policy Rule
Let’s consider the earlier example where mydaemon needs to read config.txt, which is labeled as system_data_file. If config.txt is a configuration file specific to mydaemon, a better approach might be to give it a more specific type. However, for demonstration, let’s assume it’s a shared configuration file.
First, verify the context of the file in question:
adb shell ls -Z /path/to/config.txt
Suppose the output confirms u:object_r:system_data_file:s0. Now, locate the .te file corresponding to your daemon. This is usually named after the daemon, e.g., mydaemon.te, often found in device/<vendor>/<device>/sepolicy or system/sepolicy/private within AOSP.
Add an allow rule to mydaemon.te:
# mydaemon.te (excerpt)allow mydaemon_init system_data_file:file { read getattr open };
This rule explicitly grants the mydaemon_init domain the permissions to read, get attributes (getattr), and open files of type system_data_file. It is crucial to grant only the minimum necessary permissions (principle of least privilege). Don’t grant write if only read is needed.
If config.txt is truly unique to your daemon, it’s better to define a new type for it and label the file accordingly:
# mydaemon.te (excerpt)type mydaemon_config_file, file_type, data_file_type;# In file_contexts (or similar), you would label the file:/data/misc/mydaemon/config.txt u:object_r:mydaemon_config_file:s0# Then, grant specific access:allow mydaemon_init mydaemon_config_file:file { read getattr open };
Building and Flashing the Custom Policy
After modifying the .te file(s), you need to rebuild the SELinux policy and flash it to the device.
- Rebuild Policy: Navigate to the root of your AOSP build directory and execute:
m -j$(nproc) update-sepolicyThis command rebuilds the
sepolicyand related files. - Rebuild Boot Image: If
sepolicyis part ofboot.img(older Android versions or specific device configurations) orvendor_boot.img(newer Android versions), you’ll need to rebuild and flash that partition:m -j$(nproc) bootimage # or vendorbootimage - Flash Image: Once the new image is built, flash it to your device (ensure the device is in bootloader/fastboot mode):
fastboot flash boot out/target/product/<device_name>/boot.imgOr for vendor boot:
fastboot flash vendor_boot out/target/product/<device_name>/vendor_boot.img - Reboot and Test: Reboot the device and verify that the AVC denial no longer occurs for the previously blocked action. Monitor
dmesgandlogcatclosely.
Advanced Troubleshooting and Best Practices
Leveraging `audit2allow` (Conceptual)
The audit2allow tool can automatically generate SELinux policy rules from AVC denial logs. While incredibly useful for quickly generating initial rules, it should be used with extreme caution. Blindly applying audit2allow output can lead to overly permissive policies, undermining the security benefits of SELinux.
Instead of direct application, use audit2allow as a guide to understand necessary permissions, then manually refine the rules based on the principle of least privilege.
Debugging with `sepolicy-analyze` and `sesearch`
For more complex scenarios, tools like sepolicy-analyze and sesearch (available in the AOSP development environment) are invaluable for analyzing the compiled policy.
sepolicy-analyze: Provides information about the policy itself.sesearch: Allows you to query the compiled policy for existing rules or permissions.
For example, to check if mydaemon_init already has specific permissions to system_data_file:
sepolicy-analyze -p <path_to_sepolicy.raw.txt> | sesearch -s mydaemon_init -t system_data_file -c file -p read
The sepolicy.raw.txt file is usually found in out/target/product/<device_name>/obj/ETC/sepolicy_intermediates/ after a policy build.
`neverallow` Rules and Security
Android’s SELinux policy extensively uses neverallow rules. These rules explicitly forbid certain interactions, acting as strong security guarantees. For example, a neverallow rule might prevent any application domain from directly writing to system partitions. When you introduce a custom policy, it’s possible to inadvertently violate an existing neverallow rule. The build system will flag these as errors, preventing the policy from compiling. Pay close attention to these errors, as they indicate a potential security regression.
Iterative Development and Testing
SELinux policy development is an iterative process. Start with a minimal set of necessary rules. Test the functionality, capture new AVC denials, refine your policy, and repeat. Avoid making large, sweeping changes. Always aim for the narrowest possible permission set. Utilize permissive mode during initial development to identify all denial types before switching to enforcing mode for final testing.
Conclusion
Troubleshooting SELinux AVC denials is a fundamental skill for anyone involved in Android system development, hardening, or security research. By methodically collecting and interpreting denial messages, understanding the structure of SELinux policy, and applying the principle of least privilege, you can effectively resolve policy violations. This process not only ensures the stability of your custom Android builds but also significantly enhances the overall security posture of the device by maintaining the integrity of its mandatory access control system.
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 →