El Proyecto de código abierto de Android (AOSP) proporciona una política de base sólida para las apps y los servicios comunes en todos los dispositivos Android. Los colaboradores de AOSP definen mejor esta política con frecuencia. Se espera que la política principal represente entre el 90 y el 95% de la política final en el dispositivo, y las personalizaciones específicas del dispositivo representarán entre el 5% y el 10% restante. En este artículo, se enfoca en estas personalizaciones específicas del dispositivo, cómo escribir una política específica del dispositivo y algunas de las dificultades que se deben evitar en el proceso.
Activación del dispositivo
Cuando escribas la política específica del dispositivo, sigue estos pasos.
Ejecuta en modo permisivo
Cuando un dispositivo está en modo permisivo, las denegaciones se registran, pero no se aplican. El modo permisivo es importante por dos razones:
- El modo permisivo garantiza que la incorporación de políticas no retrase otras tareas de inicio anticipado del dispositivo.
- Una denegación forzosa puede enmascarar otras denegaciones. Por ejemplo, el acceso a archivos suele implicar una búsqueda de directorios, la apertura de archivos y, luego, la lectura de archivos. En el modo de aplicación forzosa, solo se produciría el rechazo de la búsqueda de directorios. El modo permisivo garantiza que se vean todas las denegaciones.
La forma más sencilla de poner un dispositivo en modo permisivo es con la línea de comandos del kernel. Se puede agregar al archivo BoardConfig.mk
del dispositivo: platform/device/<vendor>/<target>/BoardConfig.mk
.
Después de modificar la línea de comandos, ejecuta make clean
, luego make bootimage
y, luego, escribe la nueva imagen de arranque.
Luego, confirma el modo permisivo con el siguiente comando:
adb shell getenforce
Dos semanas es un período razonable para estar en el modo permisivo global. Después de abordar la mayoría de las denegaciones, vuelve al modo de aplicación forzosa y resuelve los errores a medida que se presenten. Los dominios que aún generan rechazos o los servicios que aún están en desarrollo intensivo se pueden colocar temporalmente en el modo permisivo, pero deben volver al modo de aplicación lo antes posible.
Aplicar con anticipación
En el modo de aplicación, los rechazos se registran y aplican. La práctica recomendada es que el dispositivo esté en modo de aplicación de políticas lo antes posible. Esperar para crear y aplicar una política específica del dispositivo suele generar un producto con errores y una experiencia del usuario deficiente. Comienza con suficiente anticipación para participar en el dogfooding y garantizar una cobertura de prueba completa de la funcionalidad en el uso real. Comenzar temprano garantiza que las inquietudes de seguridad informen las decisiones de diseño. Por el contrario, otorgar permisos basados únicamente en las denegaciones observadas no es un enfoque seguro. Aprovecha este momento para realizar una auditoría de seguridad del dispositivo y registrar errores relacionados con comportamientos que no se deben permitir.
Quita o borra la política existente
Existen varios motivos para crear una política específica del dispositivo desde cero en un dispositivo nuevo, entre los que se incluyen los siguientes:
- Auditoría de seguridad
- Política demasiado permisiva
- Reducción del tamaño de las políticas
- Política de anuncios inactivos
Cómo abordar las denegaciones de servicios principales
Las denegaciones que generan los servicios principales suelen abordarse mediante el etiquetado de archivos. Por ejemplo:
avc: denied { open } for pid=1003 comm=”mediaserver” path="/dev/kgsl-3d0” dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1 avc: denied { read write } for pid=1003 name="kgsl-3d0" dev="tmpfs" scontext=u:r:mediaserver:s0 tcontext=u:object_r:device:s0 tclass=chr_file permissive=1
se aborda por completo etiquetando correctamente /dev/kgsl-3d0
. En este ejemplo, tcontext
es device
. Esto representa un
contexto predeterminado en el que todo en /dev
recibe la
etiqueta “
device”, a menos que se asigne una etiqueta más específica. Si solo aceptas el resultado de audit2allow aquí, se generará una regla incorrecta y demasiado permisiva.
Para resolver este tipo de problema, asigna al archivo una etiqueta más específica, que en este caso es gpu_device. No se necesitan más permisos, ya que mediaserver ya tiene los permisos necesarios en la política principal para acceder a gpu_device.
Otros archivos específicos del dispositivo que deben etiquetarse con tipos predefinidos en la política principal:
- dispositivos de almacenamiento en bloque
- dispositivos de audio
- dispositivos de video
- sensores
- nfc
- dispositivo_gps
- archivos en /sys
- archivos en /proc
En general, no es correcto otorgar permisos a las etiquetas predeterminadas. Muchas de estas reglas neverallow no permiten muchos de estos permisos, pero, incluso cuando no se prohíben de forma explícita, se recomienda proporcionar una etiqueta específica.
Etiqueta los servicios nuevos y las denegaciones de direcciones
Los servicios iniciados por init deben ejecutarse en sus propios dominios de SELinux. En el siguiente ejemplo, el servicio “foo” se coloca en su propio dominio de SELinux y se le otorgan permisos.
El servicio se inicia en el archivo init.device.rc
de nuestro dispositivo de la siguiente manera:
service foo /system/bin/foo class core
- Crea un dominio nuevo "foo".
Crea el archivo
device/manufacturer/device-name/sepolicy/foo.te
con el siguiente contenido:# foo service type foo, domain; type foo_exec, exec_type, file_type; init_daemon_domain(foo)
Esta es la plantilla inicial del dominio foo de SELinux, a la que puedes agregar reglas según las operaciones específicas que realiza ese ejecutable.
- Etiqueta
/system/bin/foo
Agrega lo siguiente a
device/manufacturer/device-name/sepolicy/file_contexts
:/system/bin/foo u:object_r:foo_exec:s0
Esto garantiza que el ejecutable esté etiquetado de forma correcta para que SELinux ejecute el servicio en el dominio adecuado.
- Compila y escribe en la memoria flash las imágenes de arranque y del sistema.
- Define mejor las reglas de SELinux para el dominio.
Usa denegaciones para determinar los permisos necesarios. La herramienta audit2allow proporciona buenos lineamientos, pero úsala solo para fundamentar la redacción de políticas. No solo copies el resultado.
Cómo volver al modo de aplicación forzosa
Está bien solucionar problemas en el modo permisivo, pero vuelve al modo de aplicación forzosa lo antes posible y trata de permanecer en él.
Errores comunes
Estas son algunas soluciones para los errores comunes que ocurren cuando se escriben políticas específicas del dispositivo.
Uso excesivo de la negación
La siguiente regla de ejemplo es como trabar la puerta de entrada, pero dejar las ventanas abiertas:
allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms
El objetivo es claro: todos, excepto las apps de terceros, pueden tener acceso al dispositivo de depuración.
La regla tiene algunos defectos. La exclusión de untrusted_app
es trivial, ya que todas las apps pueden ejecutar servicios de forma opcional en el dominio isolated_app
. Del mismo modo, si se agregan dominios nuevos para apps de terceros al AOSP, también tendrán acceso a scary_debug_device
.
La regla es demasiado permisiva. La mayoría de los dominios no se beneficiarán de tener acceso a esta herramienta de depuración. La regla debería haberse escrito para permitir solo los dominios que requieren acceso.
Funciones de depuración en producción
Las funciones de depuración no deben estar presentes en las compilaciones de producción ni su política.
La alternativa más simple es permitir solo la función de depuración cuando SELinux está inhabilitado en compilaciones eng/userdebug, como adb root
y adb shell setenforce 0
.
Otra alternativa segura es encerrar los permisos de depuración en una sentencia userdebug_or_eng.
Explosión del tamaño de la política
En Characterizing SEAndroid Policies in the Wild, se describe una tendencia preocupante en el crecimiento de las personalizaciones de políticas de dispositivos. La política específica del dispositivo debe representar entre el 5 y el 10% de la política general que se ejecuta en un dispositivo. Es casi seguro que las personalizaciones en el rango superior al 20%contengan dominios con privilegios excesivos y una política inactiva.
Política innecesariamente grande:
- Genera un doble impacto en la memoria, ya que la política se encuentra en el ramdisk y también se carga en la memoria del kernel.
- Desperdicia espacio en el disco, ya que requiere una imagen de arranque más grande.
- Afecta los tiempos de búsqueda de la política de tiempo de ejecución.
En el siguiente ejemplo, se muestran dos dispositivos en los que la política específica del fabricante comprendió el 50% y el 40% de la política en el dispositivo. La reescritura de la política proporcionó mejoras sustanciales de seguridad sin pérdida de funcionalidad, como se muestra a continuación. (Se incluyen los dispositivos AOSP Shamu y Flounder para comparar).
En ambos casos, la política se redujo de forma significativa en tamaño y en cantidad de permisos. La disminución del tamaño de la política se debe casi por completo a la eliminación de permisos innecesarios, muchos de los cuales probablemente eran reglas generadas por audit2allow
que se agregaron de forma indiscriminada a la política. Los dominios inactivos también fueron un problema para ambos dispositivos.
Otorga la capability dac_override
Una denegación de dac_override
significa que el proceso infractor intenta acceder a un archivo con los permisos de usuario, grupo o mundo de Unix incorrectos.
La solución adecuada casi nunca es otorgar el permiso dac_override
.
En su lugar,
cambia los permisos de Unix en el archivo o proceso. Algunos dominios, como init
, vold
y installd
, realmente necesitan la capacidad de anular los permisos de archivos de Unix para acceder a los archivos de otros procesos.
Consulta el blog de Dan Walsh para obtener una explicación más detallada.