Redacción de políticas SELinux

El Proyecto de código abierto de Android (AOSP) proporciona una política base sólida para las aplicaciones y servicios que son comunes en todos los dispositivos Android. Los contribuyentes a AOSP perfeccionan periódicamente esta política. 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 representen el 5% al ​​10% restante. Este artículo se centra en estas personalizaciones específicas del dispositivo, cómo escribir políticas específicas del dispositivo y algunos de los errores que se deben evitar en el camino.

Abrir dispositivo

Mientras redacta una 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 de activación temprana del dispositivo.
  • Una denegación forzada puede enmascarar otras denegaciones. Por ejemplo, el acceso a archivos normalmente implica una búsqueda en el directorio, la apertura del archivo y luego la lectura del archivo. En el modo obligatorio, sólo se produciría la denegación de 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 utilizar 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 inicio.

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

adb shell getenforce

Dos semanas es un tiempo razonable para estar en modo permisivo global. Después de abordar la mayoría de las denegaciones, regrese al modo de cumplimiento y solucione los errores a medida que surjan. Los dominios que aún generan denegaciones o servicios que aún se encuentran en desarrollo intenso pueden ponerse temporalmente en modo permisivo, pero vuelva a colocarlos en el modo de cumplimiento lo antes posible.

Hacer cumplir temprano

En el modo de cumplimiento, las denegaciones se registran y se aplican. Se recomienda poner su dispositivo en modo obligatorio lo antes posible. Esperar para crear y aplicar una política específica del dispositivo a menudo resulta en un producto defectuoso y una mala experiencia de usuario. Comience con suficiente anticipación para participar en la prueba interna y garantizar una cobertura de prueba completa de la funcionalidad en el uso en el mundo real. Comenzar temprano garantiza que las preocupaciones de seguridad informen las decisiones de diseño. Por el contrario, otorgar permisos basándose únicamente en denegaciones observadas es un enfoque inseguro. Utilice este tiempo para realizar una auditoría de seguridad del dispositivo y detectar errores en comportamientos que no deberían permitirse.

Eliminar o eliminar la política existente

Hay varias buenas razones para crear una política específica de dispositivo desde cero en un dispositivo nuevo, 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 completamente etiquetando 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 aquí el resultado de audit2allow daría como resultado una regla incorrecta y demasiado permisiva.

Para solucionar este tipo de problemas, asigne 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 principal 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 etiquetas predeterminadas es incorrecto. Muchos de estos permisos no están permitidos por reglas de nunca permitir , pero incluso cuando no están explícitamente prohibidos, la mejor práctica es proporcionar una etiqueta específica.

Etiquetar nuevos servicios y abordar 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 init. device .rc archivo init. device .rc como:

service foo /system/bin/foo
    class core
  1. Crea 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, a la que puede agregar reglas basadas en las operaciones específicas realizadas por ese ejecutable.

  2. Etiqueta /system/bin/foo

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

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

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

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

    Utilice denegaciones para determinar los permisos necesarios. La herramienta audit2allow proporciona buenas directrices, pero sólo se utiliza para informar la redacción de políticas. No se limite a copiar el resultado.

Volver al modo de cumplimiento

Está bien solucionar problemas en modo permisivo, pero vuelva al modo obligatorio lo antes posible e intente permanecer allí.

Errores comunes

A continuación se presentan algunas soluciones para errores comunes que ocurren al redactar políticas específicas para dispositivos.

Uso excesivo de la negación

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

allow { domain -untrusted_app } scary_debug_device:chr_file rw_file_perms

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

La regla tiene fallas en varios aspectos. Es trivial solucionar la exclusión de untrusted_app 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 sólo los dominios que requieren acceso.

Funciones de depuración en producción.

Las funciones de depuración no deberían estar presentes en las compilaciones de producción ni tampoco su política.

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

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

Explosión del tamaño de las políticas

Caracterizar las políticas de SEAndroid en la naturaleza 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 políticas inactivas.

Política innecesariamente grande:

  • Recibe un doble impacto en la memoria ya que la política se encuentra en el disco ram y también se carga en la memoria del kernel.
  • Desperdicia espacio en disco al necesitar una imagen de arranque más grande.
  • Afecta los tiempos de búsqueda de políticas en 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 del 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.

Concesión de la capacidad dac_override

Una denegación dac_override significa que el proceso infractor está intentando acceder a un archivo con permisos de usuario/grupo/mundo de Unix incorrectos. 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 Unix para acceder a los archivos de otros procesos. Consulte el blog de Dan Walsh para obtener una explicación más detallada.