Este artículo describe cómo Android maneja los problemas de compatibilidad de políticas con las plataformas OTA, donde la configuración de SELinux de la nueva plataforma puede diferir de la configuración de SELinux del proveedor anterior.
El diseño de políticas de SELinux basado en Treble considera una distinción binaria entre la plataforma y la política del proveedor ; el esquema se vuelve más complicado si las particiones de proveedores generan dependencias, como platform
< vendor
< oem
.
En Android 8.0 y versiones posteriores, la política global de SELinux se divide en componentes públicos y privados. Los componentes públicos consisten en la política y la infraestructura asociada, que se garantiza que estarán disponibles para una versión de plataforma. Esta política estará expuesta a los escritores de políticas de proveedores para permitirles crear un archivo de políticas de proveedores, que cuando se combina con la política proporcionada por la plataforma, da como resultado una política completamente funcional para un dispositivo.
- Para el control de versiones, la política pública de la plataforma exportada se escribirá como atributos .
- Para facilitar la redacción de políticas, los tipos exportados se transformarán en atributos versionados como parte del proceso de creación de políticas. Los tipos públicos también se pueden usar directamente en decisiones de etiquetado proporcionadas por archivos de contextos de proveedores.
Android mantiene una asignación entre los tipos concretos exportados en la política de la plataforma y los atributos de versión correspondientes para cada versión de la plataforma . Esto garantiza que cuando los objetos se etiquetan con un tipo, no se interrumpe el comportamiento garantizado por la política de plataforma pública en una versión anterior. Este mapeo se mantiene manteniendo un archivo de mapeo actualizado para cada versión de la plataforma , que mantiene la información de membresía de atributos para cada tipo exportado en la política pública.
Propiedad y etiquetado de objetos
Al personalizar la política en Android 8.0 y versiones posteriores, la propiedad debe estar claramente definida para cada objeto para mantener la plataforma y la política del proveedor separadas. Por ejemplo, si el proveedor etiqueta /dev/foo
y la plataforma luego etiqueta /dev/foo
en una OTA posterior, habrá un comportamiento indefinido. Para SELinux, esto se manifiesta como una colisión de etiquetado. El nodo del dispositivo solo puede tener una única etiqueta que se resuelva en la etiqueta que se aplique en último lugar. Como resultado:
- Los procesos que necesitan acceso a la etiqueta aplicada sin éxito perderán el acceso al recurso.
- Los procesos que obtienen acceso al archivo pueden fallar porque se creó el nodo de dispositivo incorrecto.
Las propiedades del sistema también tienen potencial para colisiones de nombres que podrían resultar en un comportamiento indefinido en el sistema (así como para el etiquetado de SELinux). Las colisiones entre las etiquetas de la plataforma y del proveedor pueden ocurrir para cualquier objeto que tenga una etiqueta de SELinux, incluidas las propiedades, los servicios, los procesos, los archivos y los sockets. Para evitar estos problemas, defina claramente la propiedad de estos objetos.
Además de las colisiones de etiquetas, los nombres de atributos/tipos de SELinux también pueden colisionar. Una colisión de nombre de tipo/atributo siempre dará como resultado un error del compilador de políticas.
Espacio de nombres de tipo/atributo
SELinux no permite múltiples declaraciones del mismo tipo/atributo. La política con declaraciones duplicadas no podrá compilarse. Para evitar colisiones de tipos y nombres de atributos, todas las declaraciones de proveedores deben tener un espacio de nombres que comience con np_
.
type foo, domain; → type np_foo, domain;
Propiedad del sistema y propiedad del etiquetado del proceso
Evitar las colisiones de etiquetado se resuelve mejor utilizando espacios de nombres de propiedades. Para identificar fácilmente las propiedades de la plataforma y evitar conflictos de nombres al cambiar el nombre o agregar propiedades de la plataforma exportada, asegúrese de que todas las propiedades de los proveedores tengan sus propios prefijos:
Tipo de propiedad | Prefijos aceptables |
---|---|
propiedades de control | ctl.vendor. ctl.start$vendor. ctl.stop$vendor. init.svc.vendor. |
de lectura y escritura | vendor. |
solo lectura | ro.vendor. ro.boot. ro.hardware. |
persistente | persist.vendor. |
Los proveedores pueden seguir usando ro.boot.*
(que proviene de la línea de comandos del kernel) y ro.hardware.*
(una propiedad obvia relacionada con el hardware).
Todos los servicios de proveedor en archivos init rc deben tener vendor.
para servicios en archivos init rc de particiones que no son del sistema. Se aplican reglas similares a las etiquetas de SELinux para las propiedades del proveedor ( vendor_
para las propiedades del proveedor).
Propiedad del archivo
La prevención de colisiones de archivos es un desafío porque la plataforma y la política del proveedor suelen proporcionar etiquetas para todos los sistemas de archivos. A diferencia de la denominación de tipos, el espacio de nombres de los archivos no es práctico ya que muchos de ellos son creados por el núcleo. Para evitar estas colisiones, siga la guía de nomenclatura para sistemas de archivos en esta sección. Para Android 8.0, estas son recomendaciones sin cumplimiento técnico. En el futuro, Vendor Test Suite (VTS) hará cumplir estas recomendaciones.
sistema (/sistema)
Solo la imagen del sistema debe proporcionar etiquetas para los componentes /system
a través de file_contexts
, service_contexts
, etc. Si se agregan etiquetas para los componentes /system
en la política /vendor
, es posible que no sea posible una actualización OTA solo del marco.
Vendedor (/vendedor)
La política de SELinux de AOSP ya etiqueta partes de la partición del vendor
con las que interactúa la plataforma, lo que permite escribir reglas de SELinux para que los procesos de la plataforma puedan hablar y/o acceder a partes de la partición vendor
. Ejemplos:
/vendor | Etiqueta proporcionada por la plataforma | Procesos de plataforma en función de la etiqueta |
---|---|---|
/vendor(/. * )? | vendor_file | Todos los clientes HAL en framework, ueventd , etc. |
/vendor/framework(/. * )? | vendor_framework_file | dex2oat , appdomain , etc. |
/vendor/app(/. * )? | vendor_app_file | dex2oat , installd , idmap , etc. |
/vendor/overlay(/. * ) | vendor_overlay_file | system_server , zygote , idmap , etc. |
Como resultado, se deben seguir reglas específicas (aplicadas a través de neverallows
) al etiquetar archivos adicionales en la partición vendor
:
-
vendor_file
debe ser la etiqueta predeterminada para todos los archivos en la particiónvendor
. La política de la plataforma requiere esto para acceder a las implementaciones HAL de acceso directo. - Todos los nuevos
exec_types
agregados en la particiónvendor
a través del proveedor SEPolicy deben tener el atributovendor_file_type
. Esto se aplica a través de neverallows. - Para evitar conflictos con futuras actualizaciones de plataforma/marco, evite etiquetar archivos que no sean
exec_types
en la particiónvendor
. - Todas las dependencias de biblioteca para las HAL del mismo proceso identificadas por AOSP deben etiquetarse como
same_process_hal_file.
Procfs (/proc)
Los archivos en /proc
pueden etiquetarse usando solo la etiqueta genfscon
. En Android 7.0, tanto la plataforma como la política del proveedor usaban genfscon
para etiquetar archivos en procfs
.
Recomendación: Solo etiquetas de política de plataforma /proc
. Si los procesos vendor
necesitan acceso a archivos en /proc
que actualmente están etiquetados con la etiqueta predeterminada ( proc
), la política del proveedor no debe etiquetarlos explícitamente y, en su lugar, debe usar el tipo de proc
genérico para agregar reglas para los dominios del proveedor. Esto permite que las actualizaciones de la plataforma se adapten a las futuras interfaces del kernel expuestas a través de procfs
y las etiquete explícitamente según sea necesario.
Depuración (/sys/kernel/debug)
Debugfs
se pueden etiquetar tanto en file_contexts
como genfscon
. En Android 7.0 a Android 10, tanto la plataforma como el proveedor etiquetan debugfs
.
En Android 11, no se puede acceder debugfs
ni montarlos en dispositivos de producción. Los fabricantes de dispositivos deben eliminar debugfs
.
Rastreos (/sys/kernel/debug/tracing)
Tracefs
se pueden etiquetar tanto en file_contexts
como genfscon
. En Android 7.0, solo la plataforma etiqueta tracefs
.
Recomendación: Solo la plataforma puede etiquetar tracefs
.
sysfs (/sys)
Los archivos en /sys
pueden etiquetarse usando file_contexts
y genfscon
. En Android 7.0, tanto la plataforma como el proveedor usan file_contexts
y genfscon
para etiquetar archivos en sysfs
.
Recomendación: la plataforma puede etiquetar los nodos sysfs
que no son específicos del dispositivo. De lo contrario, solo el proveedor puede etiquetar archivos.
tmpfs (/dev)
Los archivos en /dev
pueden estar etiquetados en file_contexts
. En Android 7.0, tanto la plataforma como el proveedor etiquetan los archivos aquí.
Recomendación: el proveedor puede etiquetar solo archivos en /dev/vendor
(por ejemplo, /dev/vendor/foo
, /dev/vendor/socket/bar
).
Raíces (/)
Los archivos en /
pueden etiquetarse en file_contexts
. En Android 7.0, tanto la plataforma como el proveedor etiquetan los archivos aquí.
Recomendación: Solo el sistema puede etiquetar archivos en /
.
datos (/datos)
Los datos se etiquetan a través de una combinación de file_contexts
y seapp_contexts
.
Recomendación: no permitir el etiquetado de proveedores fuera /data/vendor
. Solo la plataforma puede etiquetar otras partes de /data
.
Atributos de compatibilidad
La política de SELinux es una interacción entre los tipos de origen y destino para permisos y clases de objetos específicos. Cada objeto (procesos, archivos, etc.) afectado por la política de SELinux puede tener solo un tipo, pero ese tipo puede tener múltiples atributos.
La política está escrita principalmente en términos de tipos existentes:
allow source_type target_type:target_class permission(s);
Esto funciona porque la póliza fue escrita con conocimiento de todo tipo. Sin embargo, si la política del proveedor y la política de la plataforma usan tipos específicos, y la etiqueta de un objeto específico cambia solo en una de esas políticas, la otra puede contener una política que obtuvo o perdió el acceso en el que se basó anteriormente. Por ejemplo:
File_contexts: /sys/A u:object_r:sysfs:s0 Platform: allow p_domain sysfs:class perm; Vendor: allow v_domain sysfs:class perm;
Podría cambiarse a:
File_contexts: /sys/A u:object_r:sysfs_A:s0
Aunque la política del proveedor seguiría siendo la misma, v_domain
perdería el acceso debido a la falta de política para el nuevo tipo sysfs_A
.
Al definir una política en términos de atributos, podemos dar al objeto subyacente un tipo que tenga un atributo correspondiente a la política tanto para la plataforma como para el código del proveedor. Esto se puede hacer para todos los tipos para crear efectivamente una política de atributo en la que nunca se usen tipos concretos. En la práctica, esto es necesario solo para las partes de la política que se superponen entre la plataforma y el proveedor, que se definen y proporcionan como política pública de plataforma que se crea como parte de la política del proveedor.
La definición de políticas públicas como atributos versionados satisface dos objetivos de compatibilidad de políticas:
- Asegúrese de que el código del proveedor siga funcionando después de la actualización de la plataforma . Se logra al agregar atributos a tipos concretos para objetos correspondientes a aquellos en los que se basó el código del proveedor, preservando el acceso.
- Capacidad para desaprobar la política . Se logra delineando claramente los conjuntos de políticas en atributos que se pueden eliminar tan pronto como la versión a la que corresponden ya no sea compatible. El desarrollo puede continuar en la plataforma, sabiendo que la política anterior todavía está presente en la política del proveedor y se eliminará automáticamente cuando/si se actualiza.
Escritura de políticas
Para cumplir con el objetivo de no requerir el conocimiento de cambios de versión específicos para el desarrollo de políticas, Android 8.0 incluye una asignación entre los tipos de políticas públicas de plataforma y sus atributos. El tipo foo
se asigna al atributo foo_v N
, donde N
es la versión de destino. vN
corresponde a la variable de compilación PLATFORM_SEPOLICY_VERSION
y tiene el formato MM.NN
, donde MM
corresponde al número de SDK de la plataforma y NN
es una versión específica de la política de la plataforma.
Los atributos en la política pública no están versionados, sino que existen como una API en la que la plataforma y la política del proveedor pueden construirse para mantener estable la interfaz entre las dos particiones. Tanto los redactores de políticas de la plataforma como los de los proveedores pueden continuar redactando políticas tal como se redactan hoy.
Política pública de plataforma exportada como allow source_foo target_bar: class perm ;
se incluye como parte de la política de proveedores. Durante la compilación (que incluye la versión correspondiente) se transforma en la política que irá a la parte del dispositivo del proveedor (que se muestra en el Lenguaje Intermedio Común (CIL) transformado):
(allow source_foo_vN target_bar_vN (class (perm)))
Como la política del proveedor nunca está por delante de la plataforma, no debe preocuparse por las versiones anteriores. Sin embargo, la política de la plataforma necesitará saber qué tan atrás está la política del proveedor, incluir atributos para sus tipos y establecer la política correspondiente a los atributos versionados.
Diferencias de política
La creación automática de atributos agregando _v N
al final de cada tipo no hace nada sin la asignación de atributos a tipos en las diferencias de versión. Android mantiene un mapeo entre versiones para atributos y un mapeo de tipos para esos atributos. Esto se hace en los archivos de asignación antes mencionados con declaraciones, como (CIL):
(typeattributeset foo_vN (foo))
Actualizaciones de la plataforma
La siguiente sección detalla los escenarios para las actualizaciones de la plataforma.
Mismos tipos
Este escenario ocurre cuando un objeto no cambia las etiquetas en las versiones de la política. Esto es lo mismo para los tipos de origen y de destino y se puede ver con /dev/binder
, que tiene la etiqueta binder_device
en todas las versiones. Se representa en la política transformada como:
binder_device_v1 … binder_device_vN
Al actualizar de v1
→ v2
, la política de la plataforma debe contener:
type binder_device; -> (type binder_device) (in CIL)
En el archivo de mapeo v1 (CIL):
(typeattributeset binder_device_v1 (binder_device))
En el archivo de mapeo v2 (CIL):
(typeattributeset binder_device_v2 (binder_device))
En la política de proveedores v1 (CIL):
(typeattribute binder_device_v1) (allow binder_device_v1 …)
En la política de proveedores v2 (CIL):
(typeattribute binder_device_v2) (allow binder_device_v2 …)
Nuevos tipos
Este escenario ocurre cuando la plataforma ha agregado un nuevo tipo, lo que puede ocurrir al agregar nuevas funciones o durante el endurecimiento de la política.
- Nueva función . Cuando el tipo etiqueta un objeto que antes no existía (como un nuevo proceso de servicio), el código del proveedor no interactuó previamente con él directamente, por lo que no existe la política correspondiente. El nuevo atributo correspondiente al tipo no tiene un atributo en la versión anterior y, por lo tanto, no necesitaría una entrada en el archivo de asignación destinado a esa versión.
- Endurecimiento de políticas . Cuando el tipo representa el endurecimiento de la política, el nuevo atributo de tipo debe vincularse a una cadena de atributos correspondiente al anterior (similar al ejemplo anterior cambiando
/sys/A
desysfs
asysfs_A
). El código del proveedor se basa en una regla que permite el acceso asysfs
y debe incluir esa regla como un atributo del nuevo tipo.
Al actualizar de v1
→ v2
, la política de la plataforma debe contener:
type sysfs_A; -> (type sysfs_A) (in CIL) type sysfs; (type sysfs) (in CIL)
En el archivo de mapeo v1 (CIL):
(typeattributeset sysfs_v1 (sysfs sysfs_A))
En el archivo de mapeo v2 (CIL):
(typeattributeset sysfs_v2 (sysfs)) (typeattributeset sysfs_A_v2 (sysfs_A))
En la política de proveedores v1 (CIL):
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
En la política de proveedores v2 (CIL):
(typeattribute sysfs_A_v2) (allow … sysfs_A_v2 …) (typeattribute sysfs_v2) (allow … sysfs_v2 …)
Tipos eliminados
Este escenario (poco frecuente) ocurre cuando se elimina un tipo, lo que puede suceder cuando el objeto subyacente:
- Permanece pero recibe una etiqueta diferente.
- Se quita por la plataforma.
Durante la relajación de la política, se elimina un tipo y el objeto etiquetado con ese tipo recibe una etiqueta diferente que ya existe. Esto representa una fusión de asignaciones de atributos: el código del proveedor aún debe poder acceder al objeto subyacente por el atributo que solía poseer, pero el resto del sistema ahora debe poder acceder a él con su nuevo atributo.
Si el atributo al que se ha cambiado es nuevo, el reetiquetado es el mismo que en el caso del nuevo tipo, excepto que cuando se utiliza una etiqueta existente, la adición del antiguo atributo al nuevo tipo provocaría que otros objetos también se etiquetaran con este tipo. para ser recién accesible. Esto es esencialmente lo que hace la plataforma y se considera una compensación aceptable para mantener la compatibilidad.
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Ejemplo de versión 1: Tipos colapsados (eliminando sysfs_A)
Al actualizar de v1
→ v2
, la política de la plataforma debe contener:
type sysfs; (type sysfs) (in CIL)
En el archivo de mapeo v1 (CIL):
(typeattributeset sysfs_v1 (sysfs)) (type sysfs_A) # in case vendors used the sysfs_A label on objects (typeattributeset sysfs_A_v1 (sysfs sysfs_A))
En el archivo de mapeo v2 (CIL):
(typeattributeset sysfs_v2 (sysfs))
En la política de proveedores v1 (CIL):
(typeattribute sysfs_A_v1) (allow … sysfs_A_v1 …) (typeattribute sysfs_v1) (allow … sysfs_v1 …)
En la política de proveedores v2 (CIL):
(typeattribute sysfs_v2) (allow … sysfs_v2 …)
Ejemplo Versión 2: Eliminación completa (tipo foo)
Al actualizar de v1
→ v2
, la política de la plataforma debe contener:
# nothing - we got rid of the type
En el archivo de mapeo v1 (CIL):
(type foo) #needed in case vendors used the foo label on objects (typeattributeset foo_v1 (foo))
En el archivo de mapeo v2 (CIL):
# nothing - get rid of it
En la política de proveedores v1 (CIL):
(typeattribute foo_v1) (allow foo …) (typeattribute sysfs_v1) (allow sysfs_v1 …)
En la política de proveedores v2 (CIL):
(typeattribute sysfs_v2) (allow sysfs_v2 …)
Nueva clase/permisos
Este escenario ocurre cuando una actualización de plataforma introduce nuevos componentes de política que no existen en versiones anteriores. Por ejemplo, cuando Android agregó el administrador de objetos servicemanager
que creó los permisos para agregar, buscar y enumerar, los demonios de proveedores que deseaban registrarse con el servicemanager
necesitaban permisos que no estaban disponibles. En Android 8.0, solo la política de la plataforma puede agregar nuevas clases y permisos.
Para permitir que todos los dominios que podrían haber sido creados o ampliados por la política del proveedor utilicen la nueva clase sin obstrucciones, la política de la plataforma debe incluir una regla similar a:
allow {domain -coredomain} *:new_class perm;
Esto puede incluso requerir una política que permita el acceso para todos los tipos de interfaz (política pública), para asegurarse de que la imagen del proveedor obtenga acceso. Si esto da como resultado una política de seguridad inaceptable (como puede haber ocurrido con los cambios del administrador de servicios), se podría forzar una actualización del proveedor.
Clases/permisos eliminados
Este escenario ocurre cuando se elimina un administrador de objetos (como el administrador de objetos ZygoteConnection
) y no debería causar problemas. La clase y los permisos del administrador de objetos podrían permanecer definidos en la política hasta que la versión del proveedor ya no los use. Esto se hace agregando las definiciones al archivo de mapeo correspondiente.
Personalización del proveedor para tipos nuevos/reetiquetados
Los nuevos tipos de proveedores están en el centro del desarrollo de políticas de proveedores, ya que son necesarios para describir nuevos procesos, archivos binarios, dispositivos, subsistemas y datos almacenados. Como tal, es imperativo permitir la creación de tipos definidos por el proveedor.
Como la política del proveedor es siempre la más antigua en el dispositivo, no es necesario convertir automáticamente todos los tipos de proveedores en atributos en la política. La plataforma no se basa en nada etiquetado en la política del proveedor porque la plataforma no tiene conocimiento de ello; sin embargo, la plataforma proporcionará los atributos y tipos públicos que utiliza para interactuar con objetos etiquetados con estos tipos (como domain
, sysfs_type
, etc.). Para que la plataforma continúe interactuando correctamente con estos objetos, los atributos y tipos deben aplicarse correctamente y es posible que sea necesario agregar reglas específicas a los dominios personalizables (como init
).
Cambios de atributos para Android 9
Los dispositivos que se actualizan a Android 9 pueden usar los siguientes atributos, pero los dispositivos que se inician con Android 9 no deben hacerlo.
Atributos del infractor
Android 9 incluye estos atributos relacionados con el dominio:
-
data_between_core_and_vendor_violators
. Atributo para todos los dominios que violen el requisito de no compartir archivos por ruta entrevendor
ycoredomains
. Los procesos de plataforma y proveedor no deben usar archivos en disco para comunicarse (ABI inestable). Recomendación:- El código del proveedor debe usar
/data/vendor
. - El sistema no debe usar
/data/vendor
.
- El código del proveedor debe usar
-
system_executes_vendor_violators
. Atributo para todos los dominios del sistema (excepto los dominiosinit
yshell domains
) que violan el requisito de no ejecutar binarios de proveedores. La ejecución de binarios de proveedores tiene una API inestable. La plataforma no debe ejecutar archivos binarios de proveedores directamente. Recomendación:- Dichas dependencias de la plataforma en los binarios del proveedor deben estar detrás de las HAL de HIDL.
O
-
coredomains
que necesitan acceso a los binarios del proveedor deben moverse a la partición del proveedor y, por lo tanto, dejar de sercoredomain
.
- Dichas dependencias de la plataforma en los binarios del proveedor deben estar detrás de las HAL de HIDL.
Atributos que no son de confianza
Las aplicaciones que no son de confianza que alojan código arbitrario no deberían tener acceso a los servicios de HwBinder, excepto aquellas que se consideren lo suficientemente seguras para acceder desde dichas aplicaciones (consulte los servicios seguros a continuación). Las dos razones principales de esto son:
- Los servidores de HwBinder no realizan la autenticación del cliente porque HIDL actualmente no expone la información de UID de la persona que llama. Incluso si HIDL expuso dichos datos, muchos servicios de HwBinder operan a un nivel inferior al de las aplicaciones (como HAL) o no deben depender de la identidad de la aplicación para la autorización. Por lo tanto, para estar seguro, la suposición predeterminada es que cada servicio de HwBinder trata a todos sus clientes como igualmente autorizados para realizar las operaciones ofrecidas por el servicio.
- Los servidores HAL (un subconjunto de los servicios de HwBinder) contienen código con una tasa de incidencia más alta de problemas de seguridad que los componentes
system/core
y tienen acceso a las capas inferiores de la pila (hasta el hardware), lo que aumenta las oportunidades para eludir el modelo de seguridad de Android. .
Servicios seguros
Los servicios seguros incluyen:
-
same_process_hwservice
. Estos servicios (por definición) se ejecutan en el proceso del cliente y, por lo tanto, tienen el mismo acceso que el dominio del cliente en el que se ejecuta el proceso. -
coredomain_hwservice
. Estos servicios no presentan riesgos asociados con la razón #2. -
hal_configstore_ISurfaceFlingerConfigs
. Este servicio está específicamente diseñado para ser utilizado por cualquier dominio. -
hal_graphics_allocator_hwservice
. Estas operaciones también las ofrece el serviciosurfaceflinger
Binder, al que se permite el acceso de las aplicaciones. -
hal_omx_hwservice
. Esta es una versión HwBinder del servicio Bindermediacodec
, a la que las aplicaciones pueden acceder. -
hal_codec2_hwservice
. Esta es una versión más nueva dehal_omx_hwservice
.
Atributos utilizables
Todos hwservices
que no se consideran seguros tienen el atributo untrusted_app_visible_hwservice
. Los servidores HAL correspondientes tienen el atributo untrusted_app_visible_halserver
. Los dispositivos que se inician con Android 9 NO DEBEN usar ningún atributo untrusted
.
Recomendación:
- En su lugar, las aplicaciones que no son de confianza deberían hablar con un servicio del sistema que habla con el proveedor HIDL HAL. Por ejemplo, las aplicaciones pueden hablar con
binderservicedomain
, luegomediaserver
(que es unbinderservicedomain
) a su vez habla conhal_graphics_allocator
.O
- Las aplicaciones que necesitan acceso directo a las HAL
vendor
deben tener su propio dominio de política definida por el proveedor.
Pruebas de atributos de archivo
Android 9 incluye pruebas de tiempo de compilación que garantizan que todos los archivos en ubicaciones específicas tengan los atributos adecuados (por ejemplo, todos los archivos en sysfs
tienen el atributo sysfs_type
requerido).
Plataforma-política pública
La política de plataforma pública es el núcleo para cumplir con el modelo de arquitectura de Android 8.0 sin simplemente mantener la unión de las políticas de plataforma de v1 y v2. Los proveedores están expuestos a un subconjunto de la política de la plataforma que contiene tipos y atributos utilizables y reglas sobre esos tipos y atributos que luego pasan a formar parte de la política del proveedor (es decir, vendor_sepolicy.cil
).
Los tipos y las reglas se traducen automáticamente en la política generada por el proveedor en attribute_v N
, de modo que todos los tipos proporcionados por la plataforma son atributos con versión (sin embargo, los atributos no tienen versión). La plataforma es responsable de asignar los tipos concretos que proporciona a los atributos apropiados para garantizar que la política del proveedor continúe funcionando y que se incluyan las reglas proporcionadas para una versión en particular. La combinación de la política pública de la plataforma y la política del proveedor satisface el objetivo del modelo de arquitectura de Android 8.0 de permitir compilaciones independientes de plataformas y proveedores.
Asignación a cadenas de atributos
Cuando se utilizan atributos para asignar versiones de políticas, un tipo se asigna a uno o varios atributos, lo que garantiza que los objetos etiquetados con el tipo sean accesibles a través de los atributos correspondientes a sus tipos anteriores.
Mantener el objetivo de ocultar la información de la versión al autor de la política significa generar automáticamente los atributos con versión y asignarlos a los tipos apropiados. En el caso común de tipos estáticos, esto es sencillo: type_foo
se asigna a type_foo_v1
.
Para un cambio de etiqueta de objeto como sysfs
→ sysfs_A
o mediaserver
→ audioserver
, la creación de esta asignación no es trivial (y se describe en los ejemplos anteriores). Los mantenedores de políticas de la plataforma deben determinar cómo crear el mapeo en los puntos de transición para los objetos, lo que requiere comprender la relación entre los objetos y sus etiquetas asignadas y determinar cuándo ocurre esto. Para la compatibilidad con versiones anteriores, esta complejidad debe administrarse en el lado de la plataforma, que es la única partición que puede actualizarse.
Mejoras de versión
Para simplificar, la plataforma Android lanza una versión de política de privacidad cuando se corta una nueva rama de lanzamiento. Como se describió anteriormente, el número de versión está contenido en PLATFORM_SEPOLICY_VERSION
y tiene el formato MM.nn
, donde MM
corresponde al valor SDK y nn
es un valor privado mantenido en /platform/system/sepolicy.
Por ejemplo, 19.0
para Kitkat, 21.0
para Lollipop, 22.0
para Lollipop-MR1, 23.0
para Marshmallow, 24.0
para Nougat, 25.0
para Nougat-MR1, 26.0
para Oreo, 27.0
para Oreo-MR1 y 28.0
para Android 9. Las actualizaciones no son siempre números enteros. Por ejemplo, si un aumento de MR a una versión requiere un cambio incompatible en system/sepolicy/public
pero no un aumento de API, entonces esa versión de sepolicy podría ser: vN.1
. La versión presente en una rama de desarrollo es una 10000.0
que nunca se utilizará en dispositivos de envío.
Android puede desaprobar la versión más antigua al actualizar. Para obtener información sobre cuándo dejar de usar una versión, Android puede recopilar la cantidad de dispositivos con políticas de proveedores que ejecutan esa versión de Android y aún reciben actualizaciones importantes de la plataforma. Si el número es inferior a un determinado umbral, esa versión queda obsoleta.
Impacto en el rendimiento de múltiples atributos
Como se describe en https://github.com/SELinuxProject/cil/issues/9 , una gran cantidad de atributos asignados a un tipo generan problemas de rendimiento en caso de que se pierda la caché de políticas.
Se confirmó que esto era un problema en Android, por lo que se realizaron cambios en Android 8.0 para eliminar los atributos agregados a la política por el compilador de políticas, así como para eliminar los atributos no utilizados. Estos cambios resolvieron las regresiones de rendimiento.
System_ext public y política pública de producto
A partir de Android 11, las particiones system_ext y product pueden exportar sus tipos públicos designados a la partición del proveedor. Al igual que la política pública de la plataforma, el proveedor utiliza tipos y reglas que se traducen automáticamente en los atributos versionados, por ejemplo, de type
a type_ N
, donde N
es la versión de la plataforma con la que se crea la partición del proveedor.
Cuando las particiones system_ext y product se basan en la misma versión de plataforma N
, el sistema de compilación genera archivos de mapeo base para system_ext/etc/selinux/mapping/ N .cil
y product/etc/selinux/mapping/ N .cil
, que contienen identidad asignaciones de type
a type_ N
. El proveedor puede acceder type
con el atributo versionado type_ N
.
En caso de que solo se actualicen las particiones system_ext y product, digamos N
a N+1
(o posterior), mientras el proveedor permanece en N
, el proveedor puede perder el acceso a los tipos de particiones system_ext y product. Para evitar roturas, las particiones system_ext y product deben proporcionar archivos de mapeo de tipos concretos a atributos type_ N
. Cada socio es responsable de mantener los archivos de asignación, si van a admitir N
proveedor con N+1
(o posterior) system_ext y particiones de producto.
Para ello, se espera que los socios:
- Copie los archivos de mapeo base generados desde
N
system_ext y particiones de productos a su árbol de origen. - Modifique los archivos de mapeo según sea necesario.
- Instale los archivos de asignación en
N+1
(o posterior) system_ext y particiones de productos.
Por ejemplo, suponga que N
system_ext tiene un tipo público llamado foo_type
. Entonces system_ext/etc/selinux/mapping/ N .cil
en la partición N
system_ext se verá así:
(typeattributeset foo_type_N (foo_type)) (expandtypeattribute foo_type_N true) (typeattribute foo_type_N)
Si bar_type
se agrega a N+1
system_ext, y si bar_type
debe asignarse a foo_type
para N
proveedor, N .cil
se puede actualizar desde
(typeattributeset foo_type_N (foo_type))
a
(typeattributeset foo_type_N (foo_type bar_type))
y luego instalado en la partición de N+1
system_ext. N
proveedor puede seguir accediendo a foo_type
y bar_type
de N+1
system_ext.
Etiquetado de contextos de SELinux
Para respaldar la distinción entre la política de plataforma y de proveedor, el sistema genera archivos de contexto de SELinux de manera diferente para mantenerlos separados.
Contextos de archivo
Android 8.0 introdujo los siguientes cambios para file_contexts
:
- Para evitar una sobrecarga de compilación adicional en el dispositivo durante el arranque,
file_contexts
deja de existir en forma binaria. En cambio, son archivos de texto de expresiones regulares legibles como{property, service}_contexts
(como eran antes de 7.0). - Los
file_contexts
se dividen entre dos archivos:-
plat_file_contexts
- Plataforma Android
file_context
que no tiene etiquetas específicas del dispositivo, excepto el etiquetado de partes de la partición/vendor
que deben etiquetarse con precisión para garantizar el correcto funcionamiento de los archivos sepolicy. - Debe residir en la partición
system
en/system/etc/selinux/plat_file_contexts
en el dispositivo y ser cargado porinit
al principio junto con el proveedorfile_context
.
- Plataforma Android
-
vendor_file_contexts
-
file_context
específico del dispositivo creado mediante la combinaciónfile_contexts
que se encuentran en los directorios a los que apuntaBOARD_SEPOLICY_DIRS
en los archivosBoardconfig.mk
del dispositivo. - Debe instalarse en
/vendor/etc/selinux/vendor_file_contexts
en la particiónvendor
y debe cargarse medianteinit
al principio junto con la plataformafile_context
.
-
-
Contextos de propiedad
En Android 8.0, property_contexts
se divide entre dos archivos:
-
plat_property_contexts
-
property_context
de la plataforma Android que no tiene etiquetas específicas del dispositivo. - Debe residir en la partición
system
en/system/etc/selinux/plat_property_contexts
y ser cargado porinit
al principio junto con el proveedorproperty_contexts
.
-
-
vendor_property_contexts
-
property_context
específico del dispositivo creado mediante la combinaciónproperty_contexts
que se encuentran en los directorios a los que apuntaBOARD_SEPOLICY_DIRS
en los archivosBoardconfig.mk
del dispositivo. - Debe residir en la partición
vendor
en/vendor/etc/selinux/vendor_property_contexts
y ser cargado porinit
al principio junto con la plataformaproperty_context
-
Contextos de servicio
En Android 8.0, service_contexts
se divide entre los siguientes archivos:
-
plat_service_contexts
-
service_context
específico de la plataforma Android para elservicemanager
.service_context
no tiene etiquetas específicas del dispositivo. - Debe residir en la partición
system
en/system/etc/selinux/plat_service_contexts
y ser cargado porservicemanager
al principio junto con el proveedorservice_contexts
.
-
-
vendor_service_contexts
-
service_context
específico del dispositivo creado mediante la combinaciónservice_contexts
que se encuentran en los directorios a los que apuntaBOARD_SEPOLICY_DIRS
en los archivosBoardconfig.mk
del dispositivo. - Debe residir en la partición
vendor
en/vendor/etc/selinux/vendor_service_contexts
y ser cargado porservicemanager
al principio junto con la plataformaservice_contexts
. - Aunque
servicemanager
busca este archivo en el momento del arranque, para un dispositivoTREBLE
totalmente compatible, losvendor_service_contexts
NO DEBEN existir. Esto se debe a que toda interacción entrevendor
y los procesossystem
DEBE pasar porhwservicemanager
/hwbinder
.
-
-
plat_hwservice_contexts
- Plataforma Android
hwservice_context
parahwservicemanager
que no tiene etiquetas específicas del dispositivo. - Debe residir en la partición
system
en/system/etc/selinux/plat_hwservice_contexts
yhwservicemanager
lo carga al principio junto convendor_hwservice_contexts
.
- Plataforma Android
-
vendor_hwservice_contexts
-
hwservice_context
específico del dispositivo creado mediante la combinaciónhwservice_contexts
que se encuentran en los directorios a los que apuntaBOARD_SEPOLICY_DIRS
en los archivosBoardconfig.mk
del dispositivo. - Debe residir en la partición
vendor
en/vendor/etc/selinux/vendor_hwservice_contexts
yhwservicemanager
lo carga al principio junto conplat_service_contexts
.
-
-
vndservice_contexts
-
service_context
específico del dispositivo paravndservicemanager
creado mediante la combinación devndservice_contexts
que se encuentran en los directorios a los que apuntaBOARD_SEPOLICY_DIRS
en elBoardconfig.mk
del dispositivo. - Este archivo debe residir en la partición
vendor
en/vendor/etc/selinux/vndservice_contexts
yvndservicemanager
lo debe cargar al principio.
-
Contextos de la aplicación
En Android 8.0, seapp_contexts
se divide en dos archivos:
-
plat_seapp_contexts
- Plataforma Android
seapp_context
que no tiene cambios específicos del dispositivo. - Debe residir en la partición del
system
en/system/etc/selinux/plat_seapp_contexts.
- Plataforma Android
-
vendor_seapp_contexts
- Extensión específica del dispositivo para la plataforma
seapp_context
creada mediante la combinación deseapp_contexts
que se encuentran en los directorios a los que apuntaBOARD_SEPOLICY_DIRS
en los archivosBoardconfig.mk
del dispositivo. - Debe residir en la partición
vendor
en/vendor/etc/selinux/vendor_seapp_contexts
.
- Extensión específica del dispositivo para la plataforma
permisos MAC
En Android 8.0, mac_permissions.xml
se divide en dos archivos:
- Plataforma
mac_permissions.xml
- Plataforma Android
mac_permissions.xml
que no tiene cambios específicos del dispositivo. - Debe residir en la partición
system
en/system/etc/selinux/.
- Plataforma Android
- No plataforma
mac_permissions.xml
- Extensión específica del dispositivo para la plataforma
mac_permissions.xml
creada a partir demac_permissions.xml
que se encuentra en los directorios señalados porBOARD_SEPOLICY_DIRS
en los archivosBoardconfig.mk
del dispositivo. - Debe residir en la partición
vendor
en/vendor/etc/selinux/.
- Extensión específica del dispositivo para la plataforma
Este artículo describe cómo Android maneja los problemas de compatibilidad de políticas con las plataformas OTA, donde la configuración de SELinux de la nueva plataforma puede diferir de la configuración de SELinux del proveedor anterior.
El diseño de políticas de SELinux basado en Treble considera una distinción binaria entre la plataforma y la política del proveedor ; el esquema se vuelve más complicado si las particiones de proveedores generan dependencias, como platform
< vendor
< oem
.
En Android 8.0 y versiones posteriores, la política global de SELinux se divide en componentes públicos y privados. Los componentes públicos consisten en la política y la infraestructura asociada, que se garantiza que estarán disponibles para una versión de plataforma. Esta política estará expuesta a los escritores de políticas de proveedores para permitirles crear un archivo de políticas de proveedores, que cuando se combina con la política proporcionada por la plataforma, da como resultado una política completamente funcional para un dispositivo.
- Para el control de versiones, la política pública de la plataforma exportada se escribirá como atributos .
- For ease of policy writing, exported types will be transformed into versioned attributes as part of the policy build process. Public types may also be used directly in labeling decisions provided by vendor contexts files.
Android maintains a mapping between exported concrete types in platform policy and the corresponding versioned attributes for each platform version . This ensures that when objects are labeled with a type, it does not break behavior guaranteed by the platform-public policy in a previous version. This mapping is maintained by keeping a mapping file up-to-date for each platform version , which keeps attribute membership information for each type exported in public policy.
Object ownership and labeling
When customizing policy in Android 8.0 and higher, ownership must be clearly defined for each object to keep platform and vendor policy separate. For example, if the vendor labels /dev/foo
and the platform then labels /dev/foo
in a subsequent OTA, there will be undefined behavior. For SELinux, this manifests as a labeling collision. The device node can have only a single label which resolves to whichever label is applied last. As a result:
- Processes that need access to the unsuccessfully applied label will lose access to the resource.
- Processes that gain access to the file may break because the wrong device node was created.
System properties also have potential for naming collisions that could result in undefined behavior on the system (as well as for SELinux labeling). Collisions between platform and vendor labels can occur for any object that has an SELinux label, including properties, services, processes, files, and sockets. To avoid these issues, clearly define ownership of these objects.
In addition to label collisions, SELinux type/attribute names may also collide. A type/attribute name collision will always result in a policy compiler error.
Type/attribute namespacing
SELinux does not allow multiple declarations of the same type/attribute. Policy with duplicate declarations will fail to compilation. To avoid type and attribute name collisions, all vendor declarations should be namespaced starting with np_
.
type foo, domain; → type np_foo, domain;
System property and process labeling ownership
Avoiding labeling collisions is best solved using property namespaces. To easily identify platform properties and avoid name conflicts when renaming or adding exported-platform properties, ensure all vendor properties have their own prefixes:
Property type | Acceptable prefixes |
---|---|
control properties | ctl.vendor. ctl.start$vendor. ctl.stop$vendor. init.svc.vendor. |
read-writable | vendor. |
read-only | ro.vendor. ro.boot. ro.hardware. |
persistent | persist.vendor. |
Vendors can continue to use ro.boot.*
(which comes from the kernel cmdline) and ro.hardware.*
(an obvious hardware-related property).
All the vendor services in init rc files should have vendor.
for services in init rc files of non-system partitions. Similar rules are applied to the SELinux labels for the vendor properties ( vendor_
for the vendor properties).
File ownership
Preventing collisions for files is challenging because platform and vendor policy both commonly provide labels for all filesystems. Unlike type naming, namespacing of files is not practical since many of them are created by the kernel. To prevent these collisions, follow the naming guidance for filesystems in this section. For Android 8.0, these are recommendations without technical enforcement. In the future, these recommendations will be enforced by the Vendor Test Suite (VTS).
System (/system)
Only the system image must provide labels for /system
components through file_contexts
, service_contexts
, etc. If labels for /system
components are added in /vendor
policy, a framework-only OTA update may not be possible.
Vendor (/vendor)
The AOSP SELinux policy already labels parts of vendor
partition the platform interacts with, which enables writing SELinux rules for platform processes to be able to talk and/or access parts of vendor
partition. Ejemplos:
/vendor path | Platform-provided label | Platform processes depending on the label |
---|---|---|
/vendor(/. * )? | vendor_file | All HAL clients in framework, ueventd , etc. |
/vendor/framework(/. * )? | vendor_framework_file | dex2oat , appdomain , etc. |
/vendor/app(/. * )? | vendor_app_file | dex2oat , installd , idmap , etc. |
/vendor/overlay(/. * ) | vendor_overlay_file | system_server , zygote , idmap , etc. |
As a result, specific rules must be followed (enforced through neverallows
) when labelling additional files in vendor
partition:
-
vendor_file
must be the default label for all files invendor
partition. The platform policy requires this to access passthrough HAL implementations. - All new
exec_types
added invendor
partition through vendor SEPolicy must havevendor_file_type
attribute. This is enforced through neverallows. - To avoid conflicts with future platform/framework updates, avoid labelling files other than
exec_types
invendor
partition. - All library dependencies for AOSP-identified same process HALs must be labelled as
same_process_hal_file.
Procfs (/proc)
Files in /proc
may be labeled using only the genfscon
label. In Android 7.0, both the platform and vendor policy used genfscon
to label files in procfs
.
Recommendation: Only platform policy labels /proc
. If vendor
processes need access to files in /proc
that are currently labeled with the default label ( proc
), vendor policy should not explicitly label them and should instead use the generic proc
type to add rules for vendor domains. This allows the platform updates to accommodate future kernel interfaces exposed through procfs
and label them explicitly as needed.
Debugfs (/sys/kernel/debug)
Debugfs
can be labeled in both file_contexts
and genfscon
. In Android 7.0 to Android 10, both platform and vendor label debugfs
.
In Android 11, debugfs
can't be accessed or mounted on production devices. Device manufacturers should remove debugfs
.
Tracefs (/sys/kernel/debug/tracing)
Tracefs
can be labeled in both file_contexts
and genfscon
. In Android 7.0, only the platform labels tracefs
.
Recommendation: Only platform may label tracefs
.
Sysfs (/sys)
Files in /sys
may be labeled using both file_contexts
and genfscon
. In Android 7.0, both platform and vendor use file_contexts
and genfscon
to label files in sysfs
.
Recommendation: The platform may label sysfs
nodes that are not device-specific. Otherwise, only vendor may label files.
tmpfs (/dev)
Files in /dev
may be labeled in file_contexts
. In Android 7.0, both platform and vendor label files here.
Recommendation: Vendor may label only files in /dev/vendor
(eg, /dev/vendor/foo
, /dev/vendor/socket/bar
).
Rootfs (/)
Files in /
may be labeled in file_contexts
. In Android 7.0, both platform and vendor label files here.
Recommendation: Only system may label files in /
.
Data (/data)
Data is labeled through a combination of file_contexts
and seapp_contexts
.
Recommendation: Disallow vendor labeling outside /data/vendor
. Only platform may label other parts of /data
.
Compatibility attributes
SELinux policy is an interaction between source and target types for specific object classes and permissions. Every object (processes, files, etc.) affected by SELinux policy may have only one type, but that type may have multiple attributes.
Policy is written mostly in terms of existing types:
allow source_type target_type:target_class permission(s);
This works because the policy was written with knowledge of all types. However, if the vendor policy and platform policy use specific types, and the label of a specific object changes in only one of those policies, the other may contain policy that gained or lost access previously relied upon. For example:
File_contexts: /sys/A u:object_r:sysfs:s0 Platform: allow p_domain sysfs:class perm; Vendor: allow v_domain sysfs:class perm;
Could be changed to:
File_contexts: /sys/A u:object_r:sysfs_A:s0
Although the vendor policy would remain the same, the v_domain
would lose access due to the lack of policy for the new sysfs_A
type.
By defining a policy in terms of attributes, we can give the underlying object a type that has an attribute corresponding to policy for both the platform and vendor code. This can be done for all types to effectively create an attribute-policy wherein concrete types are never used. In practice, this is required only for the portions of policy that overlap between platform and vendor, which are defined and provided as platform public policy that gets built as part of the vendor policy.
Defining public policy as versioned attributes satisfies two policy compatibility goals:
- Ensure vendor code continues to work after platform update . Achieved by adding attributes to concrete types for objects corresponding to those on which vendor code relied, preserving access.
- Ability to deprecate policy . Achieved by clearly delineating policy sets into attributes that can be removed as soon as the version to which they correspond no longer is supported. Development can continue in the platform, knowing the old policy is still present in the vendor policy and will be automatically removed when/if it upgrades.
Policy writability
To meet the goal of not requiring knowledge of specific version changes for policy development, Android 8.0 includes a mapping between platform-public policy types and their attributes. Type foo
is mapped to attribute foo_v N
, where N
is the version targeted. vN
corresponds to the PLATFORM_SEPOLICY_VERSION
build variable and is of the form MM.NN
, where MM
corresponds to the platform SDK number and NN
is a platform sepolicy specific version.
Attributes in public policy are not versioned, but rather exist as an API on which platform and vendor policy can build to keep the interface between the two partitions stable. Both platform and vendor policy writers can continue to write policy as it is written today.
Platform-public policy exported as allow source_foo target_bar: class perm ;
is included as part of the vendor policy. During compilation (which includes the corresponding version) it is transformed into the policy that will go to the vendor portion of the device (shown in the transformed Common Intermediate Language (CIL)):
(allow source_foo_vN target_bar_vN (class (perm)))
As vendor policy is never ahead of the platform, it should not be concerned with prior versions. However, platform policy will need to know how far back vendor policy is, include attributes to its types, and set policy corresponding to versioned attributes.
Policy diffs
Automatically creating attributes by adding _v N
to the end of each type does nothing without mapping of attributes to types across version diffs. Android maintains a mapping between versions for attributes and a mapping of types to those attributes. This is done in the aforementioned mapping files with statements, such as (CIL):
(typeattributeset foo_vN (foo))
Platform upgrades
The following section details scenarios for platform upgrades.
Same types
This scenario occurs when an object does not change labels in policy versions. This is the same for source and target types and can be seen with /dev/binder
, which is labeled binder_device
across all releases. It is represented in transformed policy as:
binder_device_v1 … binder_device_vN
When upgrading from v1
→ v2
, the platform policy must contain:
type binder_device; -> (type binder_device) (in CIL)
In the v1 mapping file (CIL):
(typeattributeset binder_device_v1 (binder_device))
In the v2 mapping file (CIL):
(typeattributeset binder_device_v2 (binder_device))
In the v1 vendor policy (CIL):
(typeattribute binder_device_v1) (allow binder_device_v1 …)
In the v2 vendor policy (CIL):
(typeattribute binder_device_v2) (allow binder_device_v2 …)
New types
This scenario occurs when the platform has added a new type, which can happen when adding new features or during policy hardening.
- New feature . When the type is labeling an object that was previously non-existent (such as a new service process), the vendor code did not previously interact with it directly so no corresponding policy exists. The new attribute corresponding to the type does not have an attribute in the previous version, and so would not need an entry in the mapping file targeting that version.
- Policy hardening . When the type represents policy hardening, the new type attribute must link back to a chain of attributes corresponding to the previous one (similar to the previous example changing
/sys/A
fromsysfs
tosysfs_A
). Vendor code relies on a rule enabling access tosysfs
, and needs to include that rule as an attribute of the new type.
When upgrading from v1
→ v2
, the platform policy must contain:
type sysfs_A; -> (type sysfs_A) (in CIL) type sysfs; (type sysfs) (in CIL)
In the v1 mapping file (CIL):
(typeattributeset sysfs_v1 (sysfs sysfs_A))
In the v2 mapping file (CIL):
(typeattributeset sysfs_v2 (sysfs)) (typeattributeset sysfs_A_v2 (sysfs_A))
In the v1 vendor policy (CIL):
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
In the v2 vendor policy (CIL):
(typeattribute sysfs_A_v2) (allow … sysfs_A_v2 …) (typeattribute sysfs_v2) (allow … sysfs_v2 …)
Removed types
This (rare) scenario occurs when a type is removed, which can happen when the underlying object:
- Remains but gets a different label.
- Is removed by the platform.
During policy loosening, a type is removed and the object labeled with that type is given a different, already-existing label. This represents a merging of attribute mappings: The vendor code must still be able to access the underlying object by the attribute it used to possess, but the rest of the system must now be able to access it with its new attribute.
If the attribute to which it has been switched is new, then relabeling is the same as in the new type case, except that when an existing label is used, the addition of the old attribute new type would cause other objects also labeled with this type to be newly accessible. This is essentially what is done by the platform and is deemed to be an acceptable tradeoff to maintain compatibility.
(typeattribute sysfs_v1) (allow … sysfs_v1 …)
Example Version 1: Collapsing types (removing sysfs_A)
When upgrading from v1
→ v2
, the platform policy must contain:
type sysfs; (type sysfs) (in CIL)
In the v1 mapping file (CIL):
(typeattributeset sysfs_v1 (sysfs)) (type sysfs_A) # in case vendors used the sysfs_A label on objects (typeattributeset sysfs_A_v1 (sysfs sysfs_A))
In the v2 mapping file (CIL):
(typeattributeset sysfs_v2 (sysfs))
In the v1 vendor policy (CIL):
(typeattribute sysfs_A_v1) (allow … sysfs_A_v1 …) (typeattribute sysfs_v1) (allow … sysfs_v1 …)
In the v2 vendor policy (CIL):
(typeattribute sysfs_v2) (allow … sysfs_v2 …)
Example Version 2: Removing completely (foo type)
When upgrading from v1
→ v2
, the platform policy must contain:
# nothing - we got rid of the type
In the v1 mapping file (CIL):
(type foo) #needed in case vendors used the foo label on objects (typeattributeset foo_v1 (foo))
In the v2 mapping file (CIL):
# nothing - get rid of it
In the v1 vendor policy (CIL):
(typeattribute foo_v1) (allow foo …) (typeattribute sysfs_v1) (allow sysfs_v1 …)
In the v2 vendor policy (CIL):
(typeattribute sysfs_v2) (allow sysfs_v2 …)
New class/permissions
This scenario occurs when a platform upgrade introduces new policy components that do not exist in previous versions. For example, when Android added the servicemanager
object manager that created the add, find, and list permissions, vendor daemons wanting to register with the servicemanager
needed permissions that were not available. In Android 8.0, only the platform policy may add new classes and permissions.
To allow all domains that could have been created or extended by vendor policy to use the new class without obstruction, the platform policy needs to include a rule similar to:
allow {domain -coredomain} *:new_class perm;
This may even require policy allowing access for all interface (public policy) types, to be sure vendor image gains access. If this results in unacceptable security policy (as it may have with the servicemanager changes), a vendor upgrade could potentially be forced.
Removed class/permissions
This scenario occurs when an object manager is removed (such as the ZygoteConnection
object manager) and should not cause issues. The object manager class and permissions could remain defined in policy until the vendor version no longer uses it. This is done by adding the definitions to the corresponding mapping file.
Vendor customization for new/relabeled types
New vendor types are at the core of vendor policy development as they are needed to describe new processes, binaries, devices, subsystems, and stored data. As such, it is imperative to allow the creation of vendor-defined types.
As vendor policy is always the oldest on the device, there is no need to automatically convert all vendor types to attributes in policy. The platform does not rely on anything labeled in vendor policy because the platform has no knowledge of it; however, the platform will provide the attributes and public types it uses to interact with objects labeled with these types (such as domain
, sysfs_type
, etc.). For the platform to continue to interact correctly with these objects, the attributes and types must be appropriately applied and specific rules may need to be added to the customizable domains (such as init
).
Attribute changes for Android 9
Devices upgrading to Android 9 can use the following attributes, but devices launching with Android 9 must not.
Violator attributes
Android 9 includes these domain-related attributes:
-
data_between_core_and_vendor_violators
. Attribute for all domains that violate the requirement of not sharing files by path betweenvendor
andcoredomains
. Platform and vendor processes shouldn't use on-disk files to communicate (unstable ABI). Recommendation:- Vendor code should use
/data/vendor
. - System should not use
/data/vendor
.
- Vendor code should use
-
system_executes_vendor_violators
. Attribute for all system domains (exceptinit
andshell domains
) that violate the requirement of not executing vendor binaries. Execution of vendor binaries has unstable API. Platform shouldn't execute vendor binaries directly. Recommendation:- Such platform dependencies on vendor binaries must be behind HIDL HALs.
OR
-
coredomains
that need access to vendor binaries should be moved to the vendor partition and thus, stop beingcoredomain
.
- Such platform dependencies on vendor binaries must be behind HIDL HALs.
Untrusted attributes
Untrusted apps that host arbitrary code shouldn't have access to HwBinder services, except those considered sufficiently safe for access from such apps (see safe services below). The two main reasons for this are:
- HwBinder servers do not perform client authentication because HIDL currently does not expose caller UID information. Even if HIDL did expose such data, many HwBinder services either operate at a level below that of apps (such as, HALs) or must not rely on app identity for authorization. Thus, to be safe, the default assumption is that every HwBinder service treats all its clients as equally authorized to perform operations offered by the service.
- HAL servers (a subset of HwBinder services) contain code with higher incidence rate of security issues than
system/core
components and have access to the lower layers of the stack (all the way down to hardware) thus increasing opportunities for bypassing the Android security model.
Safe services
Safe services include:
-
same_process_hwservice
. These services (by definition) run in the process of the client and thus have the same access as the client domain in which the process runs. -
coredomain_hwservice
. These services do not pose risks associated with reason #2. -
hal_configstore_ISurfaceFlingerConfigs
. This service is specifically designed for use by any domain. -
hal_graphics_allocator_hwservice
. These operations are also offered bysurfaceflinger
Binder service, which apps are permitted to access. -
hal_omx_hwservice
. This is a HwBinder version of themediacodec
Binder service, which apps are permitted to access. -
hal_codec2_hwservice
. This is a newer version ofhal_omx_hwservice
.
Useable attributes
All hwservices
not considered safe have the attribute untrusted_app_visible_hwservice
. The corresponding HAL servers have the attribute untrusted_app_visible_halserver
. Devices launching with Android 9 MUST NOT use either untrusted
attribute.
Recommendation:
- Untrusted apps should instead talk to a system service that talks to the vendor HIDL HAL. For example, apps can talk to
binderservicedomain
, thenmediaserver
(which is abinderservicedomain
) in turn talks to thehal_graphics_allocator
.OR
- Apps that need direct access to
vendor
HALs should have their own vendor-defined sepolicy domain.
File attribute tests
Android 9 includes build time tests that ensure all files in specific locations have the appropriate attributes (such as, all files in sysfs
have the required sysfs_type
attribute).
Platform-public policy
The platform-public policy is the core of conforming to the Android 8.0 architecture model without simply maintaining the union of platform policies from v1 and v2. Vendors are exposed to a subset of platform policy that contains useable types and attributes and rules on those types and attributes which then becomes part of vendor policy (ie vendor_sepolicy.cil
).
Types and rules are automatically translated in the vendor-generated policy into attribute_v N
such that all platform-provided types are versioned attributes (however attributes are not versioned). The platform is responsible for mapping the concrete types it provides into the appropriate attributes to ensure that vendor policy continues to function and that the rules provided for a particular version are included. The combination of platform-public policy and vendor policy satisfies the Android 8.0 architecture model goal of allowing independent platform and vendor builds.
Mapping to attribute chains
When using attributes to map to policy versions, a type maps to an attribute or multiple attributes, ensuring objects labeled with the type are accessible via attributes corresponding to their previous types.
Maintaining a goal to hide version information from the policy writer means automatically generating the versioned attributes and assigning them to the appropriate types. In the common case of static types, this is straightforward: type_foo
maps to type_foo_v1
.
For an object label change such as sysfs
→ sysfs_A
or mediaserver
→ audioserver
, creating this mapping is non-trivial (and is described in the examples above). Platform policy maintainers must determine how to create the mapping at transition points for objects, which requires understanding the relationship between objects and their assigned labels and determining when this occurs. For backwards compatibility, this complexity needs to be managed on the platform side, which is the only partition that may uprev.
Version uprevs
For simplicity, the Android platform releases an sepolicy version when a new release branch is cut. As described above, the version number is contained in PLATFORM_SEPOLICY_VERSION
and is of the form MM.nn
, where MM
corresponds to the SDK value and nn
is a private value maintained in /platform/system/sepolicy.
For example, 19.0
for Kitkat, 21.0
for Lollipop, 22.0
for Lollipop-MR1 23.0
for Marshmallow, 24.0
for Nougat, 25.0
for Nougat-MR1, 26.0
for Oreo, 27.0
for Oreo-MR1, and 28.0
for Android 9. Uprevs aren't always whole numbers. For example, if an MR bump to a versions necessitates an incompatible change in system/sepolicy/public
but not an API bump, then that sepolicy version could be: vN.1
. The version present in a development branch is a never-to-be-used-in-shipping-devices 10000.0
.
Android may deprecate oldest version when upreving. For input on when to deprecate a version, Android may collect the number of devices with vendor policies running that Android version and still receiving major platform updates. If the number is less than a certain threshold, that version is deprecated.
Performance impact of multiple attributes
As described in https://github.com/SELinuxProject/cil/issues/9 , a large number of attributes assigned to a type result in performance issues in the event of a policy cache miss.
This was confirmed to be an issue in Android, so changes were made to Android 8.0 to remove attributes added to the policy by the policy compiler, as well as to remove unused attributes. These changes resolved performance regressions.
System_ext public and product public policy
Starting from Android 11, the system_ext and product partitions are allowed to export their designated public types to the vendor partition. Like platform public policy, the vendor uses types and rules automatically translated into the versioned attributes, eg from type
into type_ N
, where N
is the version of the platform which the vendor partition is built against.
When the system_ext and product partitions are based on the same platform version N
, the build system generates base mapping files to system_ext/etc/selinux/mapping/ N .cil
and product/etc/selinux/mapping/ N .cil
, which contain identity mappings from type
to type_ N
. The vendor can access type
with the versioned attribute type_ N
.
In case that only the system_ext and product partitions are updated, say N
to N+1
(or later), while the vendor stays at N
, the vendor may lose access to the types of the system_ext and product partitions. To prevent breakage, the system_ext and product partitions should provide mapping files from concrete types into type_ N
attributes. Each partner is responsible for maintaining the mapping files, if they are going to support N
vendor with N+1
(or later) system_ext and product partitions.
To do that, partners are expected to:
- Copy the generated base mapping files from
N
system_ext and product partitions to their source tree. - Amend the mapping files as needed.
- Install the mapping files to
N+1
(or later) system_ext and product partitions.
For example, suppose that N
system_ext has one public type named foo_type
. Then system_ext/etc/selinux/mapping/ N .cil
in the N
system_ext partition will look like:
(typeattributeset foo_type_N (foo_type)) (expandtypeattribute foo_type_N true) (typeattribute foo_type_N)
If bar_type
is added to N+1
system_ext, and if bar_type
should be mapped to foo_type
for N
vendor, N .cil
can be updated from
(typeattributeset foo_type_N (foo_type))
to
(typeattributeset foo_type_N (foo_type bar_type))
and then installed to N+1
system_ext's partition. N
vendor can continue accessing to N+1
system_ext's foo_type
and bar_type
.
SELinux contexts labeling
To support the distinction between platform and vendor sepolicy, the system builds SELinux context files differently to keep them separate.
File contexts
Android 8.0 introduced the following changes for file_contexts
:
- To avoid additional compilation overhead on device during boot,
file_contexts
cease to exist in the binary form. Instead, they are readable, regular expression text file such as{property, service}_contexts
(as they were pre-7.0). - The
file_contexts
are split between two files:-
plat_file_contexts
- Android platform
file_context
that has no device-specific labels, except for labeling parts of/vendor
partition that must be labeled precisely to ensure proper functioning of the sepolicy files. - Must reside in
system
partition at/system/etc/selinux/plat_file_contexts
on device and be loaded byinit
at the start along with the vendorfile_context
.
- Android platform
-
vendor_file_contexts
- Device-specific
file_context
built by combiningfile_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must be installed at
/vendor/etc/selinux/vendor_file_contexts
invendor
partition and be loaded byinit
at the start along with the platformfile_context
.
- Device-specific
-
Property contexts
In Android 8.0, the property_contexts
is split between two files:
-
plat_property_contexts
- Android platform
property_context
that has no device-specific labels. - Must reside in
system
partition at/system/etc/selinux/plat_property_contexts
and be loaded byinit
at the start along with the vendorproperty_contexts
.
- Android platform
-
vendor_property_contexts
- Device-specific
property_context
built by combiningproperty_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/vendor_property_contexts
and be loaded byinit
at the start along with the platformproperty_context
- Device-specific
Service contexts
In Android 8.0, the service_contexts
is split between the following files:
-
plat_service_contexts
- Android platform-specific
service_context
for theservicemanager
. Theservice_context
has no device-specific labels. - Must reside in
system
partition at/system/etc/selinux/plat_service_contexts
and be loaded byservicemanager
at the start along with the vendorservice_contexts
.
- Android platform-specific
-
vendor_service_contexts
- Device-specific
service_context
built by combiningservice_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/vendor_service_contexts
and be loaded byservicemanager
at the start along with the platformservice_contexts
. - Although
servicemanager
looks for this file at boot time, for a fully compliantTREBLE
device, thevendor_service_contexts
MUST NOT exist. This is because all interaction betweenvendor
andsystem
processes MUST go throughhwservicemanager
/hwbinder
.
- Device-specific
-
plat_hwservice_contexts
- Android platform
hwservice_context
forhwservicemanager
that has no device-specific labels. - Must reside in
system
partition at/system/etc/selinux/plat_hwservice_contexts
and be loaded byhwservicemanager
at the start along with thevendor_hwservice_contexts
.
- Android platform
-
vendor_hwservice_contexts
- Device-specific
hwservice_context
built by combininghwservice_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/vendor_hwservice_contexts
and be loaded byhwservicemanager
at the start along with theplat_service_contexts
.
- Device-specific
-
vndservice_contexts
- Device-specific
service_context
for thevndservicemanager
built by combiningvndservice_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
. - This file must reside in
vendor
partition at/vendor/etc/selinux/vndservice_contexts
and be loaded byvndservicemanager
at the start.
- Device-specific
Seapp contexts
In Android 8.0, the seapp_contexts
is split between two files:
-
plat_seapp_contexts
- Android platform
seapp_context
that has no device-specific changes. - Must reside in
system
partition at/system/etc/selinux/plat_seapp_contexts.
- Android platform
-
vendor_seapp_contexts
- Device-specific extension to platform
seapp_context
built by combiningseapp_contexts
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/vendor_seapp_contexts
.
- Device-specific extension to platform
MAC permissions
In Android 8.0, the mac_permissions.xml
is split between two files:
- Platform
mac_permissions.xml
- Android platform
mac_permissions.xml
that has no device-specific changes. - Must reside in
system
partition at/system/etc/selinux/.
- Android platform
- Non-Platform
mac_permissions.xml
- Device-specific extension to platform
mac_permissions.xml
built frommac_permissions.xml
found in the directories pointed to byBOARD_SEPOLICY_DIRS
in the device'sBoardconfig.mk
files. - Must reside in
vendor
partition at/vendor/etc/selinux/.
- Device-specific extension to platform