Compatibilidad de políticas

En esta página, se describe cómo Android controla los problemas de compatibilidad de políticas con las actualizaciones de la plataforma inalámbricas (OTA), en las que los nuevos parámetros de configuración de SELinux de la plataforma pueden diferir de los parámetros de configuración de SELinux del proveedor anteriores.

Propiedad y etiquetado de objetos

La propiedad debe definirse claramente para cada objeto y mantener separadas las políticas de la plataforma y del proveedor. Por ejemplo, si las etiquetas de política del proveedor son /dev/foo y las etiquetas de política de la plataforma son /dev/foo en una OTA posterior, se produce un comportamiento indefinido, como un rechazo inesperado o, lo que es más grave, una falla de inicio. En el caso de SELinux, esto se manifiesta como una colisión de etiquetado. El nodo del dispositivo solo puede tener una etiqueta que se resuelva en la etiqueta que se aplicó por última vez. Estos fueron algunos de los resultados:

  • Los procesos que necesitan acceso a la etiqueta que no se aplicó correctamente pierden el acceso al recurso.
  • Los procesos que obtienen acceso al archivo podrían fallar porque se creó el nodo de dispositivo incorrecto.

Pueden producirse colisiones entre las etiquetas de la plataforma y las del proveedor 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, define claramente la propiedad de estos objetos.

Espacio de nombres de tipo o atributo

Además de las colisiones de etiquetas, también pueden producirse colisiones entre los nombres de los atributos y los tipos de SELinux. SELinux no permite varias declaraciones de los mismos tipos y atributos. No se puede compilar una política con declaraciones duplicadas. Para evitar conflictos de nombres de tipos y nombres de atributos, se recomienda que todas las declaraciones de proveedores comiencen con el prefijo vendor_. Por ejemplo, los proveedores deben usar type vendor_foo, domain; en lugar de type foo, domain;.

Propiedad del archivo

Evitar colisiones para los archivos es un desafío porque la política de la plataforma y del proveedor suelen proporcionar etiquetas para todos los sistemas de archivos. A diferencia de la asignación de nombres de tipos, la asignación de espacios de nombres de archivos no es práctica, ya que muchos de ellos son creados por el kernel. Para evitar estas colisiones, sigue las instrucciones de nomenclatura para los sistemas de archivos que se indican en esta sección. En Android 8.0, estas son recomendaciones sin aplicación técnica. En el futuro, el conjunto de pruebas de proveedores (VTS) aplicará estas recomendaciones.

Sistema (/system)

Solo la imagen del sistema debe proporcionar etiquetas para los componentes /system a través de file_contexts, service_contexts, etcétera. Si se agregan etiquetas para los componentes /system en la política del proveedor, es posible que no se pueda realizar una actualización inalámbrica solo del framework.

Proveedor (/vendor)

La política de SELinux del AOSP ya etiqueta partes de la partición vendor con la que interactúa la plataforma, lo que permite escribir reglas de SELinux para que los procesos de la plataforma puedan comunicarse o acceder a partes de la partición vendor. Ejemplos:

/vendor path Etiqueta proporcionada por la plataforma Procesos de la plataforma según la etiqueta
/vendor(/.*)? vendor_file Todos los clientes de HAL en el framework, ueventd, etcétera
/vendor/framework(/.*)? vendor_framework_file dex2oat, appdomain, etcétera
/vendor/app(/.*)? vendor_app_file dex2oat, installd, idmap, etcétera
/vendor/overlay(/.*) vendor_overlay_file system_server, zygote, idmap, etcétera

Como resultado, se deben seguir reglas específicas (que se aplican a través de neverallows) cuando se etiquetan archivos adicionales en la partición vendor:

  • vendor_file debe ser la etiqueta predeterminada para todos los archivos de la partición vendor. La política de la plataforma requiere esto para acceder a las implementaciones de HAL de transferencia.
  • Todos los exec_types nuevos que se agreguen en la partición vendor a través de la política del proveedor deben tener el atributo vendor_file_type. Esto se aplica a través de neverallows.
  • Para evitar conflictos con futuras actualizaciones de la plataforma o el framework, no etiquetes archivos que no sean exec_types en la partición vendor.
  • Todas las dependencias de biblioteca para los HALs del mismo proceso identificados por el AOSP deben etiquetarse como same_process_hal_file..

Procfs (/proc)

Los archivos de /proc solo se pueden etiquetar con la etiqueta genfscon. En Android 7.0, tanto la política de plataforma como la de proveedor usaban genfscon para etiquetar archivos en procfs.

Recomendación: Solo etiquetas de política de la plataforma /proc. Si los procesos del proveedor necesitan acceder a archivos en /proc que actualmente están etiquetados con la etiqueta predeterminada (proc), la política del proveedor no debe etiquetarlos de forma explícita y, en su lugar, debe usar el tipo genérico proc para agregar reglas para los dominios del proveedor. Esto permite que las actualizaciones de la plataforma admitan futuras interfaces del kernel expuestas a través de procfs y las etiqueten explícitamente según sea necesario.

Debugfs (/sys/kernel/debug)

Debugfs se puede etiquetar en file_contexts y genfscon. En Android 7.0 a Android 10, tanto la plataforma como la etiqueta del proveedor son debugfs.

En Android 11, no se puede acceder a debugfs ni activarlo en dispositivos de producción. Los fabricantes de dispositivos deben quitar debugfs.

Tracefs (/sys/kernel/debug/tracing)

Tracefs se puede etiquetar en file_contexts y genfscon. En Android 7.0, solo las etiquetas de la plataforma tracefs.

Recomendación: Solo la plataforma puede etiquetar tracefs.

Sysfs (/sys)

Los archivos en /sys se pueden etiquetar con file_contexts y genfscon. En Android 7.0, tanto la plataforma como el proveedor usan genfscon para etiquetar archivos en sysfs.

Recomendación: Es posible que la plataforma etiquete los nodos sysfs que no son específicos para el dispositivo. De lo contrario, solo el proveedor puede etiquetar los archivos.

tmpfs (/dev)

Los archivos de /dev pueden etiquetarse en file_contexts. En Android 7.0, tanto la plataforma como los archivos de etiquetas del proveedor se encuentran aquí.

Recomendación: El proveedor puede etiquetar solo los archivos en /dev/vendor (por ejemplo, /dev/vendor/foo, /dev/vendor/socket/bar).

Rootfs (/)

Los archivos de / pueden etiquetarse en file_contexts. En Android 7.0, se encuentran aquí los archivos de etiquetas de la plataforma y del proveedor.

Recomendación: Solo el sistema puede etiquetar archivos en /.

Datos (/data)

Los datos se etiquetan a través de una combinación de file_contexts y seapp_contexts.

Recomendación: No permitas el etiquetado de proveedores fuera de /data/vendor. Solo la plataforma puede etiquetar otras partes de /data.

Versión de etiquetas de Genfs

A partir del nivel de API del proveedor 202504, las etiquetas de SELinux más recientes asignadas con genfscon en system/sepolicy/compat/plat_sepolicy_genfs_ver.cil son opcionales para las particiones vendor anteriores. Esto permite que las particiones vendor más antiguas conserven su implementación existente de SEPolicy. Esto se controla con la variable BOARD_GENFS_LABELS_VERSION de Makefile, que se almacena en /vendor/etc/selinux/genfs_labels_version.txt.

Ejemplo:

  • En el nivel de API del proveedor 202404, el nodo /sys/class/udc se etiqueta como sysfs de forma predeterminada.
  • A partir del nivel de API del proveedor 202504, /sys/class/udc se etiqueta como sysfs_udc.

Sin embargo, es posible que /sys/class/udc esté en uso por particiones de vendor que usan el nivel de API 202404, ya sea con la etiqueta sysfs predeterminada o una etiqueta específica del proveedor. Etiquetar /sys/class/udc como sysfs_udc de forma incondicional podría interrumpir la compatibilidad con estas particiones de vendor. Si marcas BOARD_GENFS_LABELS_VERSION, la plataforma seguirá usando las etiquetas y los permisos anteriores para las particiones vendor más antiguas.

BOARD_GENFS_LABELS_VERSION puede ser mayor o igual que el nivel de API del proveedor. Por ejemplo, las particiones vendor que usan el nivel de API 202404 pueden establecer BOARD_GENFS_LABELS_VERSION en 202504 para adoptar las nuevas etiquetas introducidas en 202504. Consulta la lista de etiquetas genfs específicas de 202504.

Cuando se etiquetan los nodos genfscon, la plataforma debe tener en cuenta las particiones vendor más antiguas y, cuando sea necesario, implementar mecanismos de resguardo para garantizar la compatibilidad. La plataforma puede usar bibliotecas exclusivas de la plataforma para consultar la versión de las etiquetas de genfs.

Política pública de la plataforma

La política de SELinux de la plataforma se divide en privada y pública. La política de plataforma pública consta de tipos y atributos que siempre están disponibles para un nivel de API del proveedor y que actúan como una API entre la plataforma y el proveedor. Esta política se expone a los redactores de políticas de proveedores para permitir que estos creen archivos de políticas de proveedores que, cuando se combinan con la política privada de la plataforma, dan como resultado una política completamente funcional para un dispositivo. La política pública de la plataforma se define en system/sepolicy/public.

Por ejemplo, un tipo vendor_init, que representa el proceso de inicialización en el contexto del proveedor, se define en system/sepolicy/public/vendor_init.te:

type vendor_init, domain;

Los proveedores pueden consultar el tipo vendor_init para escribir reglas de políticas personalizadas:

# Allow vendor_init to set vendor_audio_prop in vendor's init scripts
set_prop(vendor_init, vendor_audio_prop)

Atributos de compatibilidad

La política de SELinux es una interacción entre los tipos de origen y de destino para permisos y clases de objetos específicos. Cada objeto (por ejemplo, procesos, archivos) afectado por la política de SELinux solo puede tener un tipo, pero ese tipo puede tener varios atributos.

La política se escribe principalmente en términos de tipos existentes. Aquí, tanto vendor_init como debugfs son tipos:

allow vendor_init debugfs:dir { mounton };

Esto funciona porque la política se escribió con conocimiento de todos los tipos. 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 en solo una de esas políticas, es posible que la otra contenga una política que obtuvo o perdió el acceso en el pasado. Por ejemplo, supongamos que la política de la plataforma etiqueta los nodos de sysfs como sysfs:

/sys(/.*)? u:object_r:sysfs:s0

La política de proveedores otorga acceso a /sys/usb, etiquetado como sysfs:

allow vendor_init sysfs:chr_file rw_file_perms;

Si se cambia la política de la plataforma para etiquetar /sys/usb como sysfs_usb, la política del proveedor sigue siendo la misma, pero vendor_init pierde el acceso a /sys/usb debido a la falta de política para el nuevo tipo sysfs_usb:

/sys/usb u:object_r:sysfs_usb:s0

Para resolver este problema, Android introduce el concepto de atributos versionados. En el tiempo de compilación, el sistema de compilación traduce automáticamente los tipos públicos de la plataforma que se usan en la política del proveedor a estos atributos con versiones. Esta traducción se habilita a través de archivos de asignación que asocian un atributo versionado con uno o más tipos públicos de la plataforma.

Por ejemplo, supongamos que /sys/usb se etiqueta como sysfs en la política de la plataforma de 202504, y la política del proveedor de 202504 otorga acceso de vendor_init a /sys/usb. En este caso:

  • La política del proveedor escribe una regla allow vendor_init sysfs:chr_file rw_file_perms;, porque /sys/usb se etiqueta como sysfs en la política de la plataforma de 202504. Cuando el sistema de compilación compila la política del proveedor, traduce automáticamente la regla a allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms;. Los atributos vendor_init_202504 y sysfs_202504 corresponden a los tipos vendor_init y sysfs, que son los tipos definidos por la plataforma.
  • El sistema de compilación genera un archivo de asignación de identidad /system/etc/selinux/mapping/202504.cil. Como las particiones system y vendor usan la misma versión de 202504, el archivo de asignación contiene asignaciones de identidad de type_202504 a type. Por ejemplo, vendor_init_202504 se asigna a vendor_init, y sysfs_202504 se asigna a sysfs:
    (typeattributeset sysfs_202504 (sysfs))
    (typeattributeset vendor_init_202504 (vendor_init))
    ...

Cuando la versión se actualiza de 202504 a 202604, se crea un nuevo archivo de asignación para las particiones de 202504 en system/sepolicy/private/compat/202504/202504.cil, que se instala en /system/etc/selinux/mapping/202504.cil para las particiones de 202604 o system más recientes.vendor Inicialmente, este archivo de asignación contiene asignaciones de identidad, como se describió anteriormente. Si se agrega una etiqueta nueva sysfs_usb para /sys/usb a la política de la plataforma 202604, se actualiza el archivo de asignación para asignar sysfs_202504 a sysfs_usb:

(typeattributeset sysfs_202504 (sysfs sysfs_usb))
(typeattributeset vendor_init_202504 (vendor_init))
...

Esta actualización permite que la regla de política del proveedor convertida allow vendor_init_202504 sysfs_202504:chr_file rw_file_perms; otorgue automáticamente acceso de vendor_init al nuevo tipo sysfs_usb.

Para mantener la compatibilidad con particiones vendor anteriores, cada vez que se agrega un nuevo tipo público, ese tipo debe asignarse a, al menos, uno de los atributos versionados en el archivo de asignación system/sepolicy/private/compat/ver/ver.cil, o bien debe aparecer en system/sepolicy/private/compat/ver/ver.ignore.cil para indicar que no hay ningún tipo coincidente en las versiones anteriores del proveedor.

La combinación de la política de la plataforma, la política del proveedor y el archivo de asignación permite que el sistema se actualice sin actualizar la política del proveedor. Además, la conversión a los atributos versionados se realiza automáticamente, por lo que la política del proveedor no necesita ocuparse del control de versiones y sigue usando los tipos públicos tal como están.

Política pública del sistema_ext y del producto

A partir de Android 11, las particiones system_ext y product pueden exportar sus tipos públicos designados a la partición vendor. Al igual que la política pública de la plataforma, la política del proveedor usa tipos y reglas que se traducen automáticamente en los atributos versionados, por ejemplo, de type a type_ver, donde ver es el nivel de la API del proveedor de la partición vendor.

Cuando las particiones system_ext y product se basan en la misma versión de la plataforma ver, el sistema de compilación genera archivos de asignación base para system_ext/etc/selinux/mapping/ver.cil y product/etc/selinux/mapping/ver.cil, que contienen asignaciones de identidad de type a type_ver. La política del proveedor puede acceder a type con el atributo con versión type_ver.

En el caso de que solo se actualicen las particiones system_ext y product, por ejemplo, de ver a ver+1 (o posterior), mientras que la partición vendor permanece en ver, es posible que la política del proveedor pierda el acceso a los tipos de las particiones system_ext y product. Para evitar interrupciones, las particiones system_ext y product deben proporcionar archivos de asignación de tipos concretos a atributos type_ver. Cada socio es responsable de mantener los archivos de asignación si admite la partición ver vendor con las particiones ver+1 (o posterior) system_ext y product.

Para instalar archivos de asignación en las particiones system_ext y product, se espera que los implementadores o proveedores de dispositivos hagan lo siguiente:

  1. Copia los archivos de asignación base generados desde las particiones ver, system_ext y product a su árbol de origen.
  2. Modifica los archivos de asignación según sea necesario.
  3. Instala los archivos de asignación en las particiones ver+1 (o posterior) system_ext y product.

Por ejemplo, supongamos que la partición 202504 system_ext tiene un tipo público llamado foo_type. Luego, system_ext/etc/selinux/mapping/202504.cil en la partición 202504 system_ext se ve de la siguiente manera:

(typeattributeset foo_type_202504 (foo_type))
(expandtypeattribute foo_type_202504 true)
(typeattribute foo_type_202504)

Si se agrega bar_type a la partición system_ext de 202604 y bar_type se debe asignar a foo_type para la partición vendor de 202504, se puede actualizar 202504.cil de (typeattributeset foo_type_202504 (foo_type)) a (typeattributeset foo_type_202504 (foo_type bar_type)) y, luego, instalarlo en la partición system_ext de 202604. La partición 202504 de vendor puede seguir accediendo a foo_type y bar_type de system_ext de 202604.

Cambios en los atributos para Android 9

Los dispositivos que se actualizan a Android 9 pueden usar los siguientes atributos, pero los dispositivos que se lanzan con Android 9 no deben hacerlo.

Atributos del infractor

Android 9 incluye los siguientes atributos relacionados con el dominio:

  • data_between_core_and_vendor_violators. Es un atributo para todos los dominios que incumplen el requisito de no compartir archivos por ruta entre vendor y coredomains. Los procesos de la plataforma y del proveedor no deben usar archivos en el disco para comunicarse (ABI inestable). Recomendación:
    • El código del proveedor debe usar /data/vendor.
    • El sistema no debe usar /data/vendor.
  • system_executes_vendor_violators. Atributo para todos los dominios del sistema (excepto init y shell domains) que incumplen el requisito de no ejecutar archivos binarios del proveedor. La ejecución de los archivos binarios del proveedor tiene una API inestable. La plataforma no debe ejecutar archivos binarios del proveedor directamente. Recomendación:
    • Estas dependencias de la plataforma en los objetos binarios del proveedor deben estar detrás de las HAL de HIDL.

      O

    • Los coredomains que necesitan acceso a los archivos binarios del proveedor se deben mover a la partición vendor y, por lo tanto, dejar de ser coredomain.

Atributos no confiables

Las apps no confiables que alojan código arbitrario no deben tener acceso a los servicios de HwBinder, excepto aquellos que se consideran lo suficientemente seguros para el acceso desde dichas apps (consulta los servicios seguros a continuación). Los dos motivos principales son los siguientes:

  1. Los servidores de HwBinder no realizan la autenticación del cliente porque HIDL actualmente no expone información del UID de la entidad llamadora. Incluso si HIDL expusiera esos datos, muchos servicios de HwBinder operan a un nivel inferior al de las apps (como los HAL) o no deben depender de la identidad de la app para la autorización. Por lo tanto, para mayor seguridad, la suposición predeterminada es que cada servicio de HwBinder trata a todos sus clientes como igualmente autorizados para realizar las operaciones que ofrece el servicio.
  2. Los servidores HAL (un subconjunto de servicios de HwBinder) contienen código con una mayor tasa de incidencia de problemas de seguridad que los componentes de system/core y tienen acceso a las capas inferiores de la pila (hasta el hardware), lo que aumenta las oportunidades de eludir el modelo de seguridad de Android.

Servicios seguros

Los servicios seguros incluyen lo siguiente:

  • 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 representan riesgos asociados con el motivo núm. 2.
  • hal_configstore_ISurfaceFlingerConfigs. Este servicio está diseñado específicamente para que lo use cualquier dominio.
  • hal_graphics_allocator_hwservice. Estas operaciones también las ofrece el servicio de Binder surfaceflinger, al que las apps tienen permiso para acceder.
  • hal_omx_hwservice: Es una versión de HwBinder del servicio de Binder mediacodec, al que las apps pueden acceder.
  • hal_codec2_hwservice, que es una versión más reciente de hal_omx_hwservice.

Atributos utilizables

Todos los 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 lancen con Android 9 NO DEBEN usar ninguno de los atributos untrusted.

Recomendación:

  • En cambio, las apps no confiables deben comunicarse con un servicio del sistema que se comunique con el HAL de HIDL del proveedor. Por ejemplo, las apps pueden hablar con binderservicedomain y, luego, mediaserver (que es un binderservicedomain) habla con hal_graphics_allocator.

    O

  • Las apps que necesitan acceso directo a los HAL de vendor deben tener su propio dominio de sepolicy definido por el proveedor.

Pruebas de atributos de archivos

Android 9 incluye pruebas de tiempo de compilación que garantizan que todos los archivos en ubicaciones específicas tengan los atributos apropiados (por ejemplo, todos los archivos en sysfs tienen el atributo sysfs_type requerido).

Etiquetado de contextos de SELinux

Para admitir la distinción entre la sepolicy de la plataforma y la del proveedor, el sistema compila los archivos de contexto de SELinux de manera diferente para mantenerlos separados.

Contextos de archivos

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 formato binario. En cambio, son archivos de texto de expresión regular legibles, como {property, service}_contexts (como eran antes de la versión 7.0).
  • Los file_contexts se dividen en dos archivos:
    • plat_file_contexts
      • Plataforma de Android file_context que no tiene etiquetas específicas del dispositivo, excepto para etiquetar partes de la partición /vendor que deben etiquetarse con precisión para garantizar el funcionamiento adecuado de los archivos sepolicy.
      • Debe residir en la partición system en /system/etc/selinux/plat_file_contexts en el dispositivo y init debe cargarlo al inicio junto con el file_context del proveedor.
    • vendor_file_contexts
      • file_context específico del dispositivo creado combinando file_contexts que se encuentra en los directorios a los que apunta BOARD_SEPOLICY_DIRS en los archivos Boardconfig.mk del dispositivo.
      • Debe instalarse en /vendor/etc/selinux/vendor_file_contexts en la partición vendor y init debe cargarlo al inicio junto con la file_context de la plataforma.

Contextos de propiedad

En Android 8.0, el archivo property_contexts se divide en dos archivos:

  • plat_property_contexts
    • property_context de la plataforma de Android que no tiene etiquetas específicas del dispositivo.
    • Debe residir en la partición system en /system/etc/selinux/plat_property_contexts y init debe cargarlo al inicio junto con property_contexts del proveedor.
  • vendor_property_contexts
    • property_context específico del dispositivo creado combinando property_contexts que se encuentra en los directorios a los que apunta BOARD_SEPOLICY_DIRS en los archivos Boardconfig.mk del dispositivo.
    • Debe residir en la partición vendor en /vendor/etc/selinux/vendor_property_contexts y init debe cargarlo al inicio junto con la property_context de la plataforma.

Contextos de servicio

En Android 8.0, el archivo service_contexts se divide en los siguientes archivos:

  • plat_service_contexts
    • service_context específico de la plataforma de Android para el servicemanager. El service_context no tiene etiquetas específicas del dispositivo.
    • Debe residir en la partición system en /system/etc/selinux/plat_service_contexts y servicemanager debe cargarlo al inicio junto con service_contexts del proveedor.
  • vendor_service_contexts
    • service_context específico del dispositivo creado combinando service_contexts que se encuentra en los directorios a los que apunta BOARD_SEPOLICY_DIRS en los archivos Boardconfig.mk del dispositivo.
    • Debe residir en la partición vendor en /vendor/etc/selinux/vendor_service_contexts y servicemanager debe cargarlo al inicio junto con la service_contexts de la plataforma.
    • Aunque servicemanager busca este archivo durante el inicio, en el caso de un dispositivo TREBLE que cumpla con todos los requisitos, el archivo vendor_service_contexts NO DEBE existir. Esto se debe a que todos los procesos de interacción entre vendor y system DEBEN pasar por hwservicemanager/hwbinder.
  • plat_hwservice_contexts
    • hwservice_context de la plataforma de Android para hwservicemanager que no tiene etiquetas específicas del dispositivo.
    • Debe residir en la partición system en /system/etc/selinux/plat_hwservice_contexts y hwservicemanager debe cargarlo al inicio junto con vendor_hwservice_contexts.
  • vendor_hwservice_contexts
    • hwservice_context específico del dispositivo creado combinando hwservice_contexts que se encuentra en los directorios a los que apunta BOARD_SEPOLICY_DIRS en los archivos Boardconfig.mk del dispositivo.
    • Debe residir en la partición vendor en /vendor/etc/selinux/vendor_hwservice_contexts y hwservicemanager debe cargarlo al inicio junto con plat_service_contexts.
  • vndservice_contexts
    • service_context específico del dispositivo para el vndservicemanager creado combinando vndservice_contexts que se encuentra en los directorios a los que apunta BOARD_SEPOLICY_DIRS en el Boardconfig.mk del dispositivo.
    • Este archivo debe residir en la partición vendor en /vendor/etc/selinux/vndservice_contexts y vndservicemanager debe cargarlo al inicio.

Contextos de Seapp

En Android 8.0, el archivo seapp_contexts se divide en dos archivos:

  • plat_seapp_contexts
    • seapp_context de la plataforma de Android que no tiene cambios específicos del dispositivo.
    • Debe residir en la partición system en /system/etc/selinux/plat_seapp_contexts..
  • vendor_seapp_contexts
    • Extensión específica del dispositivo para la plataforma seapp_context creada combinando seapp_contexts que se encuentra en los directorios a los que apunta BOARD_SEPOLICY_DIRS en los archivos Boardconfig.mk del dispositivo.
    • Debe residir en la partición vendor en /vendor/etc/selinux/vendor_seapp_contexts.

Permisos de MAC

En Android 8.0, el archivo mac_permissions.xml se divide en dos archivos:

  • Plataforma mac_permissions.xml
    • mac_permissions.xml de la plataforma de Android que no tiene cambios específicos del dispositivo.
    • Debe residir en la partición system en /system/etc/selinux/..
  • No es de la plataforma mac_permissions.xml
    • Extensión específica del dispositivo para la plataforma mac_permissions.xml compilada a partir de mac_permissions.xml que se encuentra en los directorios a los que apunta BOARD_SEPOLICY_DIRS en los archivos Boardconfig.mk del dispositivo.
    • Debe residir en la partición vendor en /vendor/etc/selinux/..

Cambios en la memoria compartida para Android 17

A partir de Android 17, los dispositivos que se lancen con las siguientes propiedades deben habilitar la capacidad de la política memfd_class y actualizar su política relacionada con la memoria compartida para admitir objetos de la clase memfd_file:

  • El nivel de API del proveedor debe ser 202604 o superior para brindarles a los proveedores y OEM la oportunidad de actualizar su política del proveedor para admitir memfd. También permite que los dispositivos existentes se actualicen a versiones más recientes de Android sin necesidad de actualizar su partición del proveedor.
  • Kernel android16-6.12 o posterior, ya que estos kernels admiten la función memfd_class, que es necesaria para implementar una política detallada para memfd.

Habilita la capacidad de política memfd_class

Hasta hace poco, SELinux etiquetaba un memfd como un archivo con el mismo tipo que su sistema de archivos de respaldo: tmpfs. Desde el punto de vista de la política, esto hacía que fuera imposible distinguir un memfd de otro archivo en un montaje de tmpfs. Ahora, SELinux etiqueta un memfd con el contexto de seguridad del proceso de asignación y los memfds se tratan como objetos de clase memfd_file. Esta funcionalidad está protegida por la capacidad de política memfd_class para conservar la retrocompatibilidad con entornos de espacio de usuario más antiguos.

Para habilitar la capacidad de la política memfd_class, crea un archivo policy_capabilities en BOARD_VENDOR_SEPOLICY_DIRS. El archivo debe contener la siguiente entrada:

# $BOARD_VENDOR_SEPOLICY_DIRS/*/policy_capabilities
policycap memfd_class;

Luego, vuelve a compilar las imágenes y escríbelas en la memoria flash del dispositivo para verificar que la capacidad esté habilitada.

Verifica que la capacidad de política memfd_class esté habilitada

Usa el siguiente comando para verificar el estado de la capacidad de la política de memfd_class:

adb shell 'cat /sys/fs/selinux/policy_capabilities/memfd_class'

Si el resultado es 1, se habilita la capacidad de la política memfd_class. De lo contrario, no se habilitará.

Transición de la política existente a memfd

Algunos procesos usaban la macro tmpfs_domain() en su política para acceder a su memfds y asignarle un espacio de nombres, por ejemplo:

# foo.te
tmpfs_domain(foo)

Esto se traduce de la siguiente manera:

# foo.te
type_transition foo tmpfs:file foo_tmpfs;
allow foo foo_tmpfs:file { read write getattr map };

y permite procesar el proceso de acceso bar como foo de la siguiente manera:memfds

# bar.te
allow bar foo_tmpfs:file { read write getattr map };

Con la capacidad de política memfd_class habilitada, ya no se necesita la macro tmpfs_domain(), ya que la política de la plataforma se actualizó para permitir que cualquier proceso cree y use su propio memfds, como se muestra aquí:

# system/sepolicy/private/domain.te
allow domain self:memfd_file { create read write getattr map };

y el proceso bar puede acceder a memfds creado por el proceso foo de la siguiente manera:

# bar.te
allow bar foo:memfd_file { read write getattr map };

Se actualizó la política de la plataforma para tener en cuenta los usos existentes de memfd. Sin embargo, la política específica del proveedor y del dispositivo que usa etiquetas tmpfs debe actualizarse para usar memfd_file. Si la política se comparte entre SoCs o dispositivos que no tienen el nivel de API del proveedor 202604 o superior, se recomienda conservar la política tmpfs heredada junto con la nueva política memfd_file para garantizar la compatibilidad.

Cómo identificar denegaciones de AVC relacionadas con memfd

Los rechazos relacionados con Memfd se pueden recuperar con el siguiente comando:

adb shell logcat -d -b events | grep memfd

Rechazos de AVC con tmpfs como destino

En el siguiente ejemplo, se muestra una denegación de avc que encontró un proceso que intentó escribir en un memfd en el que no tenía permiso para escribir:

audit(0.0:539): avc:  denied  { write } for  comm="binder:665_1" name="memfd:MessageQueue"
dev="tmpfs" ino=8324 scontext=u:r:mediacodec:s0 tcontext=u:object_r:tmpfs:s0 tclass=file
permissive=0

Cuando se habilita la capacidad de la política memfd_class, el contexto de destino de un memfd es el contexto de seguridad del proceso de asignación, no tmpfs, y la clase de destino es memfd_file, no file. Por lo tanto, si observas rechazos de avc relacionados con memfd, en los que el memfd en cuestión está etiquetado como un archivo tmpfs, la capacidad de la política de memfd_class no está habilitada.

Denegaciones de AVC con memfd_file como clase de destino

En el siguiente ejemplo, se muestra una denegación de avc que encontró un proceso que intentaba escribir en un memfd en el que no tenía permiso para escribir, y se habilitó la capacidad de la política memfd_class, así como una línea adicional que logd emite después de la denegación con la misma marca de tiempo:

audit(0.0:86): avc: denied { read } for
path=2F6D656D66643A4D6564696142756666657247726F7570202864656C6574656429 ino=512 dev=""
scontext=u:r:mediaserver:s0 tcontext=u:object_r:mediaextractor:s0 tclass=memfd_file

auditd  : Decoded path for audit(0.0:86): /memfd:MediaBufferGroup (deleted)

La marca de tiempo coincidente indica que el Decoded path for … log se relaciona con el rechazo de avc con la marca de tiempo 0.0.86. Este registro decodifica la cadena hexadecimal del valor de la ruta de acceso en el rechazo de avc y proporciona el nombre de la región de memoria memfd, lo que puede ser útil para comprender qué búfer se comparte. El contexto de origen y el contexto de destino son útiles para comprender qué procesos deben compartir memoria. En el ejemplo anterior, queda claro que el proceso mediaserver debe poder acceder al memfds de mediaextractor. Por lo tanto, la política adecuada es la siguiente:

# mediaserver.te
allow mediaserver mediaextractor:memfd_file { getattr read write map };

Actualizaciones del dominio de seguridad en Android 17

La API de ASharedMemory_create() en Android 17 implementa lógica condicional para seleccionar entre el controlador ashmem heredado y el framework de memfd para las asignaciones de memoria compartida.

En el caso de los dispositivos que cumplen con los requisitos de memfd (nivel de API del proveedor 202604 o superior y kernel android16-6.12 o posterior), la API evalúa el targetSdkVersion de la app que realiza la llamada. Si la versión del SDK de destino es 37 o posterior, se asigna un memfd. Esto permite que los desarrolladores corrijan los problemas que encuentran a medida que actualizan la versión del SDK de destino.

Si el dispositivo no cumple con los requisitos previos de memfd's, ASharedMemory recurre a ashmem. Esto mantiene la compatibilidad de los dispositivos actualizados con particiones o kernels del proveedor más antiguos.

Para aplicar esta transición, la política de SELinux de la plataforma bloquea las apps que segmentan la versión 37 del SDK o una posterior en los dominios de seguridad platform_app, priv_app y untrusted_app para que no abran /dev/ashmem ni invoquen comandos ioctl de ashmem en memfd. Esto se logra dividiendo esos dominios de la app según la versión del SDK de destino. Esto introduce los dominios de seguridad platform_app_36, priv_app_36 y untrusted_app_34, que, junto con otros dominios de la app, conservan los permisos de apertura de ashmem y la capacidad de invocar comandos ioctl de ashmem en memfds.

En una versión futura de Android, el conjunto de apps que conservan permisos para abrir el dispositivo ashmem y para invocar comandos ioctl de ashmem en memfds se reducirá solo a platform_app_36, priv_app_36 y untrusted_app_34, y a dominios de apps no confiables para versiones anteriores del SDK.

Las políticas de SELinux personalizadas del OEM o del proveedor para las apps que fijan su versión del SDK objetivo deben actualizarse para alinearse con estos cambios de dominio, como se detalla en las siguientes secciones.

Actualizaciones del dominio SELinux de platform_app

El dominio platform_app se divide según el targetSdkVersion de la app. A las apps de la plataforma que se segmentan para la versión 37 o posterior del SDK se les asigna el dominio platform_app, mientras que las que se segmentan para la versión 36 o anterior del SDK usan platform_app_36. El dominio platform_app_36 conserva la capacidad de abrir /dev/ashmem para la retrocompatibilidad. Para simplificar la administración de políticas en ambos dominios, usa el atributo platform_app_all.

Considera el caso en el que la app de la plataforma sample-plat-app necesita leer y escribir desde y hacia /dev/foo_device. La política de SELinux existente del proveedor podría verse de la siguiente manera:

# This will only allow sample-plat-app to access the device if it
# is placed in the platform_app domain (i.e. target SDK version is 37 or higher).
allow platform_app foo_device:chr_file rw_file_perms;

Sin embargo, si sample-plat-app se fija en la versión del SDK de destino 36, se coloca en el dominio platform_app_36, y la política de SELinux anterior no se aplicará, y se observará la siguiente denegación de AVC:

auditd  : type=1400 audit(0.0:11): avc:  denied  { read write } for  comm="sample-plat-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:platform_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0

Para corregir eso, la política se puede actualizar de la siguiente manera, ya que la app siempre debería tener acceso al nodo del dispositivo:

# This allows sample-plat-app to access the device independent of
# target SDK version.
allow platform_app_all foo_device:chr_file rw_file_perms;

Es posible que haya situaciones en las que platform_app_all no funcione. Por ejemplo, si la macro hal_client_domain() se usa con platform_app_all, la política no se compila. Esto se debe a que platform_app_all es un atributo y hal_client_domain() intentaría adjuntarle otro atributo, lo que no es posible:

# platform_app.te
hal_client_domain(platform_app, hal_foo)

En esos casos, es necesario usar el tipo platform_app_36 directamente, por lo que tu política debe tener el siguiente contenido:

# platform_app.te
hal_client_domain(platform_app, hal_foo)

# platform_app_36.te
hal_client_domain(platform_app_36, hal_foo)

Actualizaciones del dominio SELinux de priv_app

El dominio priv_app se divide según el targetSdkVersion de la app. A las apps con privilegios que se segmentan para la versión 37 del SDK o versiones posteriores se les asigna el dominio priv_app, mientras que las que se segmentan para la versión 36 del SDK o versiones anteriores usan priv_app_36. El dominio priv_app_36 conserva la capacidad de abrir /dev/ashmem para la retrocompatibilidad. Para simplificar la administración de políticas en ambos dominios, usa el atributo priv_app_all.

Considera el caso en el que la app de la plataforma sample-priv-app necesita leer y escribir desde y hacia /dev/foo_device. La política de SELinux existente del proveedor podría verse de la siguiente manera:

# This will only allow sample-priv-app to access the device if it
# is placed in the priv_app domain (i.e. target SDK version is 37 or higher).
allow priv_app foo_device:chr_file rw_file_perms;

Sin embargo, si sample-priv-app se fija en la versión del SDK de destino 36, se coloca en el dominio priv_app_36, y la política de SELinux anterior no se aplicará, y se observará la siguiente denegación de AVC:

auditd  : type=1400 audit(0.0:11): avc:  denied  { read write } for  comm="sample-priv-app" path="/dev/foo_device" dev="tmpfs" ino=1609 scontext=u:r:priv_app_36:s0:c512,c768 tcontext=u:object_r:foo_device:s0 tclass=chr_file permissive=0

Para corregir eso, la política se puede actualizar de la siguiente manera, ya que la app siempre debería tener acceso al nodo del dispositivo:

# This allows sample-priv-app to access the device independent of
# target SDK version.
allow priv_app_all foo_device:chr_file rw_file_perms;

Es posible que haya situaciones en las que priv_app_all no funcione. Por ejemplo, si la macro hal_client_domain() se usa con priv_app_all, la política no se compilará. Esto se debe a que priv_app_all es un atributo y hal_client_domain() intentaría adjuntarle otro atributo, lo que no es posible:

# priv_app.te
hal_client_domain(priv_app, hal_foo)

En esos casos, es necesario usar el tipo priv_app_36 directamente, por lo que tus archivos de política se verán de la siguiente manera:

# priv_app.te
hal_client_domain(priv_app, hal_foo)

# priv_app_36.te
hal_client_domain(priv_app_36, hal_foo)

Actualizaciones del dominio SELinux untrusted_app

El dominio untrusted_app se divide según el targetSdkVersion de la app. A las apps no confiables que se segmentan para la versión del SDK 37 o posterior se les asigna el dominio untrusted_app, mientras que a las que se segmentan para las versiones del SDK 34 a 36 inclusive se les asigna el nuevo dominio untrusted_app_34. El dominio untrusted_app_34, así como los dominios untrusted_app_X, en los que "X" es una versión anterior del SDK de destino, conservan la capacidad de abrir `/dev/ashmem` para la retrocompatibilidad.