Introduction: The Unseen Guardian of Android Security
In the evolving landscape of mobile security, Android’s implementation of SELinux (Security-Enhanced Linux) stands as a critical pillar. Far beyond traditional discretionary access control (DAC), SELinux enforces Mandatory Access Control (MAC) policies, providing a robust layer of defense against privilege escalation and malicious exploits. At the heart of SELinux’s power lies the concept of a “context” – a label applied to every process, file, and system resource, dictating exactly what interactions are permitted. This deep dive will unravel the intricacies of SELinux contexts, focusing on how file_contexts define initial labels and how sepolicy‘s Type Enforcement mechanism governs their interactions in the Android ecosystem.
Deconstructing the SELinux Context
An SELinux context is a string of four components: user:role:type:level. While all components play a part, the type component is the most crucial for Android’s primary security model, Type Enforcement. For example, a file might have the context u:object_r:system_file:s0.
- User (u): Represents the SELinux user, not to be confused with a Linux user ID. In Android, this is often
ufor unprivileged orsystem_ufor system processes. - Role (object_r): Defines the role, typically
object_rfor files and objects, orrfor processes. - Type (system_file): The most significant part. This is an identifier that categorizes the object or process.
system_file, for instance, denotes a file belonging to the system partition. - Level (s0): Used for Multi-Level Security (MLS) or Multi-Category Security (MCS). In Android, this is usually
s0, but can be used for isolating apps (e.g., per-app data directory levels).
Our focus will primarily be on the ‘type’ component, as it forms the basis of Type Enforcement, which dictates what actions a process of a given type can perform on an object of another given type.
file_contexts: Labeling the Filesystem
Before any process can interact with a file, that file needs an SELinux context. This initial labeling is primarily handled by file_contexts files. These files are essentially mapping tables that associate filesystem paths (or patterns) with specific SELinux types. In Android, these are typically located in the /sepolicy directory (or within the boot/vendor images for device-specific policies).
Understanding file_contexts Entries
A typical file_contexts entry looks like this:
/system/bin/my_daemon u:object_r:my_daemon_exec:s0n/data/vendor/my_app_data(/.*)? u:object_r:my_app_data_file:s0
- The first part is a regular expression matching a file path.
- The subsequent components define the SELinux user, role, type, and level for matching files.
When the system boots, or when new files are created in specific locations, the init process (or restorecon utility) applies these labels. Developers of custom ROMs or new features must ensure that any new files or directories they introduce have appropriate file_contexts entries. For instance, if you’re adding a new executable /vendor/bin/new_tool, you would need an entry like:
/vendor/bin/new_tool u:object_r:vendor_exec:s0
You can inspect the context of any file on a rooted Android device using ls -Z:
adb shellnsunls -Z /system/bin/app_process64nu:object_r:zygote_exec:s0 /system/bin/app_process64
If a file has an incorrect context, or if you’ve manually changed it, you can revert it using restorecon:
restorecon /data/local/tmp/my_test_file
sepolicy: The Rulebook of Type Enforcement
Once files and processes have their contexts, sepolicy dictates how they can interact. This is the core of Type Enforcement. The sepolicy consists of a set of rules (often hundreds or thousands) that specify which types can access which other types, and what kind of access (read, write, execute, bind, create, etc.) is permitted.
Key sepolicy Directives
type: Declares a new SELinux type. Example:type my_new_type;domain: A special type that applies to processes. Example:type my_domain, domain;allow: The most common rule. It explicitly grants permissions. Syntax:allow source_type target_type:class permissions;neverallow: Critical for security. It prevents certain interactions, even if another rule attempts to grant them. This is used to maintain a baseline of security and prevent policy developers from accidentally introducing vulnerabilities.
Consider a process running with the context u:r:my_service_domain:s0 trying to access a configuration file with the context u:object_r:my_config_file:s0. Without a specific allow rule, the access would be denied.
allow my_service_domain my_config_file:file { read write getattr };
This rule explicitly allows processes of type my_service_domain to read, write, and get attributes of files of type my_config_file.
A Practical Scenario: Securing a New System Service
Let’s walk through the steps required to properly secure a hypothetical new background service, myservice, which lives in /vendor/bin and uses a configuration file at /data/vendor/myservice.conf.
Step 1: Define New Types
First, we need to declare new SELinux types for our service’s executable, its running domain, and its configuration file in a new .te (Type Enforcement) file, typically added to your device’s sepolicy source (e.g., device/<vendor>/<device>/sepolicy/myservice.te).
# Declares the type for the executablentype myservice_exec, exec_type, file_type;nn# Declares the domain for the running servicentype myservice_domain, domain;nn# Declares the type for its configuration filentype myservice_conf_file, file_type, data_file_type;
Step 2: Update file_contexts
Next, we update the file_contexts file to label our new executable and configuration file. This would go into a file_contexts file relevant to your vendor partition (e.g., device/<vendor>/<device>/sepolicy/file_contexts).
/vendor/bin/myservice u:object_r:myservice_exec:s0n/data/vendor/myservice.conf u:object_r:myservice_conf_file:s0
Step 3: Define sepolicy Rules
Now, we write the rules that allow myservice_domain to operate correctly.
# Allow init (the process manager) to start myservicenallow init myservice_exec:file { read getattr open execute };nallow init myservice_domain:process transition;nallow myservice_domain { self }:process { execmem nosuid_transition rlimitinh siginh };nn# Allow myservice_domain to execute its own binarynallow myservice_domain myservice_exec:file { execute_no_trans read getattr open };nn# Allow myservice_domain to read and write its config filenallow myservice_domain myservice_conf_file:file { read write getattr open create unlink };nallow myservice_domain myservice_conf_file:dir { add_name write remove_name search };nn# Inherit from common Android service permissions (e.g., access to binder, logd)n# This often involves using a macro or inheriting from a common domain like system_server_domain.n# For simplicity, let's assume it inherits common permissions from core_domain via a policy macro.n# For example, if myservice uses network sockets:nallow myservice_domain self:socket { create bind listen connect read write setopt };nallow myservice_domain port:tcp_socket name_connect;
These rules ensure that the init process can start myservice, and that myservice, once running in its own domain, can execute its own binary and manage its configuration file. Additional rules would be needed based on what system resources myservice interacts with (e.g., network, other services, device nodes).
Step 4: Integrate with init.rc
Finally, you need an init.rc service entry to specify how your service is started and, crucially, to set its SELinux domain.
service myservice /vendor/bin/myservicen class vendor_servicesn user systemn group systemn seclabel u:r:myservice_domain:s0n capabilities NET_RAW DAC_OVERRIDEn oneshot
The seclabel line is critical, as it instructs init to transition myservice into the myservice_domain SELinux context when it starts.
Debugging SELinux Denials
Despite careful planning, SELinux denials are common during development. They manifest as
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 →