Introduction to Android SELinux Hardening
Android’s security architecture relies heavily on SELinux (Security-Enhanced Linux), a Mandatory Access Control (MAC) system that enforces fine-grained permissions beyond traditional Unix discretionary access control. Every process, file, and resource on an Android device has a security context, and SELinux policy dictates what interactions are allowed between these contexts. While highly effective at preventing privilege escalation and containing compromised services, developing or customizing Android can lead to a deluge of SELinux denials, often referred to as AVC (Access Vector Cache) denials. Manually sifting through these audit logs and crafting policies can be a tedious and error-prone process. This article delves into two indispensable power tools for Android SELinux policy analysis and automation: audit2allow and sesearch.
Understanding Android SELinux Audit Logs
Before diving into the tools, it’s crucial to understand where SELinux denials manifest. When an unallowed operation occurs, the SELinux kernel module logs an AVC denial. On Android, these logs are primarily visible via the kernel ring buffer (`dmesg`) or through `logcat` if an `auditd` daemon (or similar logging mechanism) is forwarding them to the Android logging system. A typical AVC denial message contains critical information:
scontext: The security context of the subject (the process initiating the action).tcontext: The security context of the target (the resource being acted upon).tclass: The class of the target (e.g., file, directory, process, socket).perms: The specific permissions that were denied (e.g., read, write, execute, open).comm: The command name of the process.pid: The process ID.
Example `dmesg` output (filtered for SELinux):
adb shell dmesg | grep "avc: denied"
[ 123.456789] audit: type=1400 audit(1234567890.123:123): avc: denied { read } for pid=1234 comm="my_daemon" name="my_file.conf" dev="tmpfs" ino=12345 scontext=u:r:my_daemon:s0 tcontext=u:object_r:system_file:s0 tclass=file permissive=0
Tool 1: Automating Policy Generation with `audit2allow`
audit2allow is a powerful utility that parses SELinux audit logs and automatically generates corresponding policy rules that would allow the denied operations. It’s an excellent starting point for quickly addressing AVC denials, but its output *must* be reviewed carefully to avoid over-permissiveness.
Step-by-Step Usage of `audit2allow`
- Capture Audit Denials: Replicate the actions that are causing SELinux denials on your Android device. While doing so, capture the `dmesg` output (or `logcat` filtered for SELinux denials).
adb shell "dmesg | grep 'avc: denied' > /data/local/tmp/selinux_denials.log"Then pull the log file to your host machine:
adb pull /data/local/tmp/selinux_denials.log - Run `audit2allow`: On your host machine (assuming you have `audit2allow` installed as part of the `selinux-policy-devel` or `policycoreutils` package), feed the log file to `audit2allow`.
audit2allow -i selinux_denials.log - Interpreting Output: `audit2allow` will output one or more SELinux Type Enforcement (TE) rules, often in a human-readable format, and sometimes also in Common Intermediate Language (CIL).
#============= my_daemon ==============allow my_daemon system_file:file { read getattr open };This output suggests that the `my_daemon` domain needs `read`, `getattr`, and `open` permissions on files labeled `system_file`.
- Generate CIL (for Android AOSP): For integration into Android’s AOSP build system, you’ll typically need CIL format. Add the `-M` flag to create `.te` and `.cil` files.
audit2allow -i selinux_denials.log -M my_custom_policyThis will create `my_custom_policy.te` (source TE rules) and `my_custom_policy.cil` (compiled CIL). The CIL file can then be included in your device’s `sepolicy` build process.
Caveats and Best Practices
While `audit2allow` is efficient, it’s a brute-force approach. Always:
- Review Manually: Do not blindly apply generated rules. They might grant more permissions than strictly necessary.
- Principle of Least Privilege: Refine the rules to grant only the minimum required permissions.
- Context Matters: Understand why the denial occurred. Was it expected behavior or an attempt at exploitation?
Tool 2: Deep Diving into Policy with `sesearch`
sesearch is a command-line tool used to query compiled SELinux policy. It allows you to understand existing rules, identify types, attributes, and permissions, and debug why certain operations might be allowed or denied. It’s invaluable for gaining insight into complex policies.
Step-by-Step Usage of `sesearch`
- Obtain Android’s Compiled Policy: The compiled SELinux policy on Android devices is typically located at `/sepolicy` (or `/vendor/etc/selinux/precompiled_sepolicy` or similar). You need to pull this to your host machine:
adb pull /sepolicy - Basic Queries:
Query all `allow` rules where `my_daemon` is the source context:
sesearch -A -s my_daemon -f sepolicyFind all rules that allow `read` permission on `file` class for `system_file` target:
sesearch -A -t system_file -c file -p read -f sepolicyList all types defined in the policy:
sesearch -T -f sepolicyList all attributes:
sesearch -AT -f sepolicyFind all types associated with a specific attribute (e.g., `domain`):
sesearch -A -attribute domain -f sepolicyIdentify the permissions associated with a particular class, for example, `file`:
sesearch -C -c file -f sepolicy - Advanced Queries for Debugging:
To understand why a `read` access was denied from `my_daemon` to `system_file:file`:
sesearch -s my_daemon -t system_file -c file -p read -f sepolicyIf this returns no results, it confirms there’s no explicit allow rule. You can then broaden your search to see if `my_daemon` is part of an attribute that *should* have access, or if `system_file` has an attribute that might be restricted.
Check if `my_daemon` type can transition to another type:
sesearch -T -s my_daemon -p transition -f sepolicy
Advanced Workflow and Best Practices
Combining `audit2allow` and `sesearch` creates a powerful iterative workflow:
- Identify Denials: Trigger the problematic behavior and capture audit logs.
- Generate Initial Rules: Use `audit2allow` to get a baseline set of rules.
- Analyze and Refine with `sesearch`: Before applying, use `sesearch` to:
- Check if similar rules already exist.
- Understand the implications of the generated rules within the broader policy.
- Verify if the `scontext` or `tcontext` should inherit permissions from an attribute.
- Ensure the generated rules adhere to the principle of least privilege by refining permissions. For instance, if `audit2allow` suggests `allow my_daemon system_file:file { read write open };`, but your daemon only needs to read a specific config file, you might refine it to `allow my_daemon system_file:file { read open };`.
- Test and Repeat: Apply the refined policy, re-run your application, and monitor for new denials. This iterative process helps build a robust and secure SELinux policy.
- Integrate into Build: For custom Android builds (AOSP), integrate your `.te` or `.cil` files into the device’s `sepolicy` build structure, typically under `device/VENDOR/DEVICE/sepolicy` or similar paths.
Conclusion
Mastering Android SELinux policy is crucial for building secure and hardened Android systems. While the complexity of MAC can be daunting, tools like `audit2allow` and `sesearch` demystify the process. `audit2allow` provides an automated first pass at policy generation, saving considerable time, while `sesearch` offers deep introspection into existing policies, enabling precise debugging and informed refinement. By combining these utilities with a strong understanding of SELinux principles and a commitment to least privilege, developers and security engineers can effectively manage and secure their Android environments, significantly enhancing device integrity and user privacy.
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 →