Escribir la política de SELinux

El Proyecto de código abierto de Android (AOSP) proporciona una política de base sólida para las aplicaciones y los servicios que son comunes en todos los dispositivos Android. Los colaboradores de AOSP refinan regularmente esta política. Se espera que la política principal constituya entre el 90% y el 95% de la política final en el dispositivo, y las personalizaciones específicas del dispositivo constituyen el 5%-10% restante. Este artículo se centra en estas personalizaciones específicas del dispositivo, cómo escribir una política específica del dispositivo y algunas de las trampas que se deben evitar en el camino.

Mostrar dispositivo

Mientras escribe la política específica del dispositivo, siga estos pasos.

Ejecutar 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 activación de políticas no retrase otras tareas iniciales de activación de dispositivos.
  • Una denegación forzada puede enmascarar otras denegaciones. Por ejemplo, el acceso a archivos generalmente implica una búsqueda de directorio, abrir un archivo y luego leerlo. En el modo de aplicación, solo se produciría la denegación de la búsqueda en el directorio. El modo permisivo garantiza que se vean todas las denegaciones.

La forma más sencilla de poner un dispositivo en modo permisivo es mediante la línea de comandos del kernel . Esto se puede agregar al archivo BoardConfig.mk del dispositivo: platform/device/<vendor>/<target>/BoardConfig.mk . Después de modificar la línea de comando, realice make clean , luego make bootimage y actualice la nueva imagen de arranque.

Después de eso, confirme el modo permisivo con:

adb shell getenforce

Dos semanas es una cantidad de tiempo razonable para estar en modo permisivo global. Después de abordar la mayoría de las denegaciones, vuelva al modo de aplicación y aborde los errores a medida que surjan. Los dominios que todavía producen denegaciones o los servicios que aún se encuentran en un proceso de desarrollo intenso pueden ponerse temporalmente en modo permisivo, pero vuelva a ponerlos en modo de aplicación tan pronto como sea posible.

Hacer cumplir temprano

En el modo de cumplimiento, las denegaciones se registran y se aplican. Es una buena práctica poner su dispositivo en modo de aplicación lo antes posible. Esperar a crear y hacer cumplir la política específica del dispositivo a menudo da como resultado un producto con errores y una mala experiencia para el usuario. Comience lo suficientemente temprano como para participar en dogfooding y garantizar una cobertura de prueba completa de la funcionalidad en el uso del mundo real. Comenzar temprano garantiza que las preocupaciones de seguridad informen las decisiones de diseño. Por el contrario, otorgar permisos basados ​​únicamente en denegaciones observadas es un enfoque inseguro. Aproveche este tiempo para realizar una auditoría de seguridad del dispositivo y presentar errores contra comportamientos que no deberían permitirse.

Eliminar o eliminar la política existente

Hay una serie de buenas razones para crear una política específica del dispositivo desde cero en un nuevo dispositivo, que incluyen:

Abordar las denegaciones de servicios básicos

Las denegaciones generadas por los servicios principales generalmente se abordan 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 soluciona por completo al etiquetar correctamente /dev/kgsl-3d0 . En este ejemplo, tcontext es device . Esto representa un contexto predeterminado donde todo en /dev recibe la etiqueta " dispositivo " a menos que se asigne una etiqueta más específica. Simplemente aceptar la salida de audit2allow aquí daría como resultado una regla incorrecta y demasiado permisiva.

Para solucionar este tipo de problema, dale al archivo una etiqueta más específica, que en este caso es gpu_device . No se necesitan más permisos ya que el servidor de medios ya tiene los permisos necesarios en la política central para acceder a gpu_device.

Otros archivos específicos del dispositivo que deben etiquetarse con tipos predefinidos en la política principal:

En general, otorgar permisos a las etiquetas predeterminadas es incorrecto. Muchos de estos permisos no están permitidos por reglas neverallow , pero incluso cuando no están explícitamente prohibidos, la mejor práctica es proporcionar una etiqueta específica.

Etiquete los nuevos servicios y aborde las denegaciones

Los servicios iniciados por Init deben ejecutarse en sus propios dominios SELinux. El siguiente ejemplo coloca el servicio "foo" en su propio dominio SELinux y le otorga permisos.

El servicio se lanza en el init. device .rc archivo como:

service foo /system/bin/foo
    class core
  1. Crear un nuevo dominio "foo"

    Cree 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 para el dominio foo SELinux, al que puede agregar reglas basadas en las operaciones específicas realizadas por ese ejecutable.

  2. Etiqueta /system/bin/foo

    Agregue lo siguiente a device/ manufacturer / device-name /sepolicy/file_contexts :

    /system/bin/foo   u:object_r:foo_exec:s0
    

    Esto asegura que el ejecutable esté debidamente etiquetado para que SELinux ejecute el servicio en el dominio adecuado.

  3. Cree y actualice las imágenes de arranque y del sistema.
  4. Refine las reglas de SELinux para el dominio.

    Utilice las denegaciones para determinar los permisos necesarios. La herramienta audit2allow proporciona buenas pautas, pero úsela solo para informar la redacción de políticas. No se limite a copiar la salida.

Cambiar de nuevo al modo de ejecución

Está bien solucionar problemas en el modo permisivo, pero vuelva al modo de aplicación lo antes posible e intente permanecer allí.

Errores comunes

Aquí hay algunas soluciones para errores comunes que ocurren al escribir políticas específicas del dispositivo.

Uso excesivo de la negación

La siguiente regla de ejemplo es como cerrar la puerta principal pero dejar las ventanas abiertas:

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

La intención es clara: todos menos las aplicaciones de terceros pueden tener acceso al dispositivo de depuración.

La regla es defectuosa en algunos aspectos. La exclusión de untrusted_app es trivial porque todas las aplicaciones pueden ejecutar opcionalmente servicios en el dominio isolated_app . Del mismo modo, si se agregan nuevos dominios para aplicaciones de terceros a 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 tampoco su política.

La alternativa más simple es permitir solo la función de depuración cuando SELinux está deshabilitado en compilaciones de eng/userdebug, como adb root y adb shell setenforce 0 .

Otra alternativa segura es incluir los permisos de depuración en una instrucción userdebug_or_eng .

Explosión del tamaño de la póliza

La caracterización de SEAndroid Policies in the Wild describe una tendencia preocupante en el crecimiento de las personalizaciones de políticas de dispositivos. La política específica del dispositivo debe representar del 5 al 10 % de la política general que se ejecuta en un dispositivo. Es casi seguro que las personalizaciones en el rango de más del 20% contienen dominios privilegiados y políticas inactivas.

Póliza innecesariamente grande:

  • Recibe un doble golpe 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 disco al necesitar una imagen de arranque más grande.
  • Afecta a los tiempos de búsqueda de políticas de tiempo de ejecución.

El siguiente ejemplo muestra dos dispositivos en los que la política específica del fabricante comprendía el 50 % y el 40 % de la política en el dispositivo. Una reescritura de la política produjo mejoras de seguridad sustanciales sin pérdida de funcionalidad, como se muestra a continuación. (Los dispositivos AOSP Shamu y Flounder se incluyen para comparar).

Figura 1: Comparación del tamaño de la política específica del dispositivo después de la auditoría de seguridad.

Figura 1 . Comparación del tamaño de la política específica del dispositivo después de la auditoría de seguridad.

En ambos casos, la política se redujo drásticamente tanto en tamaño como en número de permisos. La disminución en el tamaño de la política se debe casi en su totalidad a la eliminación de permisos innecesarios, muchos de los cuales probablemente eran reglas generadas por audit2allow que se agregaron indiscriminadamente a la política. Los dominios muertos también fueron un problema para ambos dispositivos.

Otorgando la capacidad dac_override

Una denegación de dac_override significa que el proceso infractor está intentando acceder a un archivo con los permisos incorrectos de usuario/grupo/mundo de Unix. La solución adecuada casi nunca es otorgar el permiso dac_override . En su lugar , cambie los permisos de Unix en el archivo o proceso . Algunos dominios como init , vold e installd realmente necesitan la capacidad de anular los permisos de archivos de Unix para acceder a los archivos de otros procesos. Consulte el blog de Dan Walsh para obtener una explicación más detallada.