tree: b5c6c05c9743004580477f6c9ae060e887dcc62e [path history] [tgz]
  1. access_vectors
  2. apmanager.te
  3. attributes
  4. avahi.te
  5. bluetoothtbd.te
  6. brillo.te
  7. brillo_service.te
  8. brillo_setup.te
  9. brilloaudioservice.te
  10. crash_reporter.te
  11. dbus.te
  12. device.te
  13. dhcp.te
  14. fake-nvram.te
  15. file_contexts
  16. firewalld.te
  17. firewalld_client.te
  18. kernel.te
  19. metrics_collector.te
  20. metrics_event_reporting.te
  21. metrics_reporting.te
  22. metricsd.te
  23. nativeperms.te
  24. nativepowerman.te
  25. os_release.te
  26. peripheralman.te
  27. property_contexts
  29. security_classes
  30. sensorservice.te
  31. service.te
  32. service_contexts
  33. shill.te
  34. shill_client.te
  35. te_macros
  36. tlsdated.te
  37. tpm_managerd.te
  38. trunksd.te
  39. trunksd_client.te
  40. update_engine.te
  41. update_engine_client.te
  42. weave.te
  43. weave_client.te
  44. webservd.te
  45. webservd_client.te
  46. webservd_testc.te
  47. wifi_setup.te
  48. wpa.te

SELinux in Brillo

What is SELinux?

SELinux is an implementation of a Mandatory Access Control (MAC) mechanism. It provides fine-grained control over allowed process behavior by defining a system-wide security policy.

The most important concept in SELinux is the concept of a domain. A domain specifies what a process can do on the system; it can be understood as a grouping of permissions. The system-wide security policy is composed of all the domains defined in the system, with their permissions.

Why SElinux?

Brillo is based on Android, and tries to remain as close to a strict subset of Android as possible. Android uses SELinux to enforce its security policy, so Brillo does the same.

Hacking with SELinux

By default, Brillo is configured in enforcing mode, which means that processes must be specifically granted permissions. The first thing a new process needs is a domain to run in. Brillo provides a sample domain for user-written Brillo services in the brillo_service.te file:

type brillo_service, domain;
type brillo_service_exec, exec_type, file_type;

# To use 'brillo_service' as the domain for your service,
# label the service's executable as 'brillo_service_exec' in the 'file_contexts'
# file in this directory.
# brillo_domain() below ensures that executables labelled 'brillo_service_exec'
# will be put in the 'brillo_service' domain at runtime.

# Allow domain transition from init, and access to D-Bus and Binder.
# See 'te_macros' in this directory for details.

Files describing domains use the extension .te. Domains are expressed as types in SELinux, so .te (type enforcement) files describe what rules are enforced for that type (domain).

Every process in the system is labelled with a domain label. Files on the system are also labelled with a single file type. A process can be put in a specific domain using two mechanisms:

  • By calling an SELinux function from the process.
  • By labelling the process' executable file and defining an automatic transition rule between the label of the file on disk and the label of the process' runtime domain.

In brillo_service.te, the brillo_domain macro tells the system to always put processes executed from files labelled as brillo_service_exec in the brillo_service domain.

For this automatic transition to work, files have to be labelled correctly. File labelling happens in the file_contexts file:

/system/bin/firewalld      u:object_r:firewalld_exec:s0

/data/misc/apmanager(/.*)? u:object_r:apmanager_data_file:s0
/system/bin/apmanager      u:object_r:apmanager_exec:s0

If you‘re adding a new service, you need to add the service’s executable to the file_contexts file and then adding a matching .te file in the same directory. For most user-written services, the brillo_service domain should be a good starting point.


Your service might also require access to the Binder IPC mechanism.

To be able to add the required policy line to your service's .te file, first define a type for the Binder service in the service.te file. Then, use that type to label the Binder interface the process is trying to add.

  • Define the type for the Binder service in the service.te file:

      # Add a context for brillo_service.
      type brilloservice, service_manager_type;
  • Label the interface with this type in the service_contexts file:

      # Associate brillo_service's name (as defined when it is added
      # to the service manager) with a context.
      android.brillo.BrilloService u:object_r:brilloservice:s0
  • Add the following lines to the .te file (brillo_service.te in this example) to allow the domain to add the Binder service:

      # Allow the service to add itself to service_manager.
      allow brillo_service brilloservice:service_manager add;

This procedure allows the brillo_service domain to add services labeled brilloservice to servicemanager.

Configuring SELinux permissions

It‘s likely that your service will require access to resources not covered by the brillo_service domain. In that case, you will see error messages like this on your device’s logs:

firewalld: type=1400 audit(0.0:9): avc: denied { search } for name="proc" dev="debugfs" ino=15882 scontext=u:r:firewalld:s0 tcontext=u:object_r:debugfs:s0 tclass=dir permissive=0

You can use the audit2allow command to translate these errors to SELinux policy lines that can be added to the .te file:

$ audit2allow -i {file with error messages} -p ${ANDROID_PRODUCT_OUT}/root/sepolicy


Common recipes/access to common services

Naming conventions

  • allow_call_{service} for services exposed over binder.
  • use_{resource|service} for other services or resources.