Android System Securing, Hardening, & Privacy

SELinux for Custom Daemons: Securing Your Own System Services in Android ROMs

Google AdSense Native Placement - Horizontal Top-Post banner

Introduction: The Imperative of SELinux in Custom Android ROMs

In the landscape of custom Android ROM development, introducing new system services or daemons is a common practice to extend functionality. However, integrating these services without proper security considerations can introduce significant vulnerabilities. This is where SELinux (Security-Enhanced Linux) becomes indispensable. Android has leveraged SELinux since version 4.3 to enforce Mandatory Access Control (MAC), significantly hardening the system against privilege escalation and unauthorized access. For custom daemons, simply dropping an executable into /system/bin is not enough; without a tailored SELinux policy, your service will either be blocked by existing rules or, worse, inherit an overly permissive context, becoming a prime target for exploits.

This article provides an expert-level guide to writing, auditing, and enforcing SELinux policies for your custom daemons within an Android ROM, ensuring your services operate with the principle of least privilege.

Understanding SELinux Fundamentals in Android

SELinux operates on the principle of contexts, where every process, file, and IPC mechanism has an associated security context. A context typically consists of user:role:type:sensitivity, with type being the most critical component for access control decisions. The policy defines rules that specify which types can interact with other types (e.g., a process of type foo_t can read files of type bar_file_t).

  • Type Enforcement (TE): The core of SELinux, defining permissions between types.
  • File Contexts: Map file paths to specific SELinux types. These are crucial for ensuring your executables, configuration files, and data directories are correctly labeled.
  • Policy Enforcement Modes:
    • Enforcing: All access denials are enforced.
    • Permissive: Access denials are logged but not enforced. Essential for policy development.

Case Study: Securing ‘my_custom_service’

Let’s assume we have a custom daemon, my_custom_service, which needs to run as a system service, read its configuration from /vendor/etc/my_custom_service.conf, write logs to /data/vendor/my_custom_service/log.txt, and communicate via a Unix domain socket with a specific client.

Step 1: Define the Daemon’s Execution Context (.te file)

First, we create a new type enforcement file, typically named my_custom_service.te. This file will define the domain for our service.

# my_custom_service.te in system/sepolicy/public or vendor/etc/selinux/my_custom_service.te (for vendor partition) # Type definition for our custom service type my_custom_service_t; # Inherit properties from core domains for process execution type_transition init my_custom_service_exec_t:process my_custom_service_t; # Allow init to execute our service (init will fork/exec) domain_auto_trans(init, my_custom_service_exec_t, my_custom_service_t); # Allow the service to be a domain (process) domain_type(my_custom_service_t); # Allow basic capabilities required by most services allow my_custom_service_t self:capability { chown dac_override fsetid setgid setuid sys_nice sys_tty_config }; # Allow standard IPC for logging and binder services allow my_custom_service_t logd:unix_stream_socket connectto; allow my_custom_service_t servicemanager:binder call; allow my_custom_service_t system_server:binder call;

Step 2: Define File Contexts

Next, we need to inform SELinux how to label our service’s executable, configuration, and data files. These definitions go into a file_contexts file (e.g., system/sepolicy/public/file_contexts or vendor/etc/selinux/my_custom_service_file_contexts).

# File contexts for my_custom_service /system/bin/my_custom_service u:object_r:my_custom_service_exec_t:s0 /vendor/etc/my_custom_service.conf u:object_r:my_custom_service_conf_t:s0 /data/vendor/my_custom_service(/.*)? u:object_r:my_custom_service_data_t:s0

We also need to define the new file types:

# my_custom_service_file.te (can be part of my_custom_service.te) type my_custom_service_exec_t; type my_custom_service_conf_t; type my_custom_service_data_t; file_type(my_custom_service_exec_t); file_type(my_custom_service_conf_t); file_type(my_custom_service_data_t); # Allow the service to read its configuration file allow my_custom_service_t my_custom_service_conf_t:file { read open getattr }; # Allow the service to create, read, write its data/log files allow my_custom_service_t my_custom_service_data_t:dir { create search add_name write remove_name rmdir }; allow my_custom_service_t my_custom_service_data_t:file { create read write append getattr setattr unlink }; # Allow dir creation in /data/vendor/my_custom_service allow my_custom_service_t vendor_data_file:dir { create_dir_perms };

Step 3: Initial Policy Development (Permissive Mode)

During development, boot your ROM in permissive mode by adding androidboot.selinux=permissive to your kernel command line. This allows the system to log denials without blocking operations. Run your my_custom_service and exercise all its functionalities. Then, collect SELinux audit messages:

adb shell

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 →
Google AdSense Inline Placement - Content Footer banner