Introduction to SELinux in Android
Security-Enhanced Linux (SELinux) is a mandatory access control (MAC) system that provides a robust layer of security on top of Android’s discretionary access control (DAC). For custom ROM developers, understanding and effectively managing SELinux policies is not just good practice – it’s crucial for device stability and security. Misconfigured or incomplete SELinux policies are a common source of system instability, app crashes, and boot loops in custom Android builds. This article provides a comprehensive debugging playbook to help you diagnose and resolve SELinux policy conflicts.
Android leverages SELinux to enforce isolation between system components, applications, and hardware resources. Every process and file on an Android system has a security context, and SELinux policies define exactly what interactions are allowed between these contexts. When a process attempts an action (e.g., reading a file, binding to a port, executing a program) that isn’t explicitly permitted by the policy, SELinux denies the action, logs an Audit Vector Cache (AVC) message, and often results in unexpected behavior from the offending process.
Understanding SELinux Denials
Anatomy of an AVC Denial
An AVC denial message is your primary tool for debugging. These messages are logged in the kernel ring buffer and are typically visible via dmesg or logcat. Understanding its components is key to crafting the correct policy rule:
scontext(Source Context): The security context of the process attempting the action.tcontext(Target Context): The security context of the resource being accessed.tclass(Target Class): The type of resource being accessed (e.g.,file,dir,socket,process,service).perm(Permissions): The specific permission that was denied (e.g.,read,write,execute,getattr,bind,call).comm(Command): The name of the command or process that triggered the denial.pid(Process ID): The PID of the process that triggered the denial.
Here’s an example of an AVC denial:
type=1400 audit(1678886400.123:456): avc: denied { read } for pid=1234 comm="myservice" name="mydata.txt" dev="dm-0" ino=7890 scontext=u:r:myservice_t:s0 tcontext=u:object_r:unlabeled:s0 tclass=file permissive=0
From this, we learn: myservice (myservice_t) tried to read a file (mydata.txt) which currently has the unlabeled context. This is a common scenario when new files or partitions are introduced without proper SELinux labeling.
Common Denial Scenarios
- New Files/Directories: Access to files or directories created by a custom service or app that don’t have an appropriate
file_contextsentry. - New Processes/Services: A custom daemon starting without its own domain or attempting to interact with other domains without permission.
- IPC (Inter-Process Communication): Services trying to bind to sockets, use binder services, or communicate via other IPC mechanisms.
- Hardware Access: Custom drivers or HALs attempting to access device nodes (e.g.,
/dev/mydevice) without proper policy.
The SELinux Debugging Playbook
Step 1: Capture Denial Logs
The first step is to get the full AVC denial messages. You can do this in several ways:
- Using
dmesg(Kernel Buffer):adb shell dmesg | grep 'avc:'This shows kernel-level messages, including AVC denials. It’s often the most reliable source.
- Using
logcat(Android Log Buffer):adb logcat | grep 'avc:'While
dmesgtypically captures all AVCs,logcatcan also show them, sometimes with additional context from the Android logging system. - Persistent Log Storage: For complex issues, it’s best to redirect to a file:
adb shell "dmesg -c | grep 'avc:' > /data/local/tmp/avc_denials.log"Then pull the file:
adb pull /data/local/tmp/avc_denials.log .This clears the kernel buffer (`-c`) after reading, ensuring you only get new denials for subsequent tests.
If your device is stuck in a boot loop due to SELinux, you might need to boot into a recovery mode or temporarily set SELinux to permissive mode (if possible via boot arguments) to gather logs.
Step 2: Analyze the AVC Message
Once you have the denial, parse its components. Focus on scontext, tcontext, tclass, and perm. These tell you exactly *who* tried *what* to *whom* and *how* it failed.
For example: scontext=u:r:system_server:s0 tcontext=u:object_r:my_new_device:s0 tclass=chr_file perm=read
Here, the system_server process tried to read a character device file labeled my_new_device. The task is now to either allow system_server to read my_new_device, or re-label my_new_device if its current label is incorrect.
Step 3: Identify the Source and Target Types
Before writing a new rule, verify the existing definitions. Android’s SELinux policy is built from hundreds of .te (type enforcement) files. You’ll primarily work within the /external/sepolicy and /device/<vendor>/<device>/sepolicy directories of your AOSP source tree.
- Search for type definitions:
grep -rAndroid 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 →