Cómo STACKLEAK mejora la seguridad del kernel de Linux

STACKLEAK es una característica de seguridad del kernel de Linux desarrollada originalmente por los creadores de Grsecurity / PaX. Decidí llevar STACKLEAK al núcleo oficial de vainilla (línea principal del núcleo de Linux). Este artículo hablará sobre la estructura interna, las propiedades de esta función de seguridad y su ruta muy larga y difícil en la línea principal.





STACKLEAK protege contra varias clases de vulnerabilidades en el kernel de Linux, a saber:

  • reduce la información que es útil para el atacante, que puede filtrarse de la pila nuclear al espacio del usuario;
  • bloquea algunos ataques a variables no inicializadas en la pila del kernel;
  • proporciona herramientas de detección de desbordamiento de pila dinámica.

Esta característica de seguridad encaja perfectamente con el concepto de Kernel Self Protection Project (KSPP): la seguridad es más que solo corregir errores. Absolutamente todos los errores en el código no pueden repararse y, por lo tanto, el kernel de Linux debería funcionar de manera segura en situaciones de error, incluso al tratar de explotar vulnerabilidades. Más detalles sobre KSPP están disponibles en la wiki del proyecto .

STACKLEAK está presente como PAX_MEMORY_STACKLEAK en el parche grsecurity / PaX. Sin embargo, el parche grsecurity / PaX ha dejado de distribuirse libremente desde abril de 2017. Por lo tanto, la aparición de STACKLEAK en el kernel de vainilla sería valiosa para los usuarios de Linux con mayores requisitos de seguridad de la información.

Orden de trabajo:

  • seleccione STACKLEAK del parche grsecurity / PaX,
  • estudia el código cuidadosamente y forma un parche,
  • enviar a LKML, obtener comentarios, mejorar, repetir nuevamente antes de ser aceptado en la línea principal.

Al momento de escribir (25 de septiembre de 2018), se envió la versión 15 de una serie de parches . Contiene una parte y un código arquitectónicamente independientes para x86_64 y x86_32. El soporte de STACKLEAK para arm64, desarrollado por Laura Abbott de Red Hat, ya ha logrado ingresar al núcleo de vainilla 4.19.

STACKLEAK: características de seguridad


Borrar información residual en la pila del núcleo


Esta medida reduce la información útil que pueden producir algunas fugas de la pila nuclear al espacio del usuario.

Un ejemplo de fuga de información de la pila del núcleo se presenta en la Figura 1.



Esquema 1.

Sin embargo, las fugas de este tipo se vuelven inútiles si, al final de una llamada al sistema, la parte utilizada de la pila del núcleo se llena con un valor fijo (Figura 2).



Esquema 2.

Como resultado, STACKLEAK bloquea algunos ataques a variables no inicializadas en la pila del kernel. Ejemplos de tales vulnerabilidades: CVE-2017-17712, CVE-2010-2963. Se puede encontrar una descripción de la metodología de explotación para CVE-2010-2963 en un artículo de Kees Cook.

La figura 3 muestra la esencia del ataque a una variable no inicializada en la pila del kernel.



Esquema 3.

STACKLEAK bloquea los ataques de este tipo, ya que el valor que llena la pila nuclear al final de una llamada al sistema indica un área no utilizada en el espacio de direcciones virtuales (Figura 4).



Esquema 4.

Una limitación importante es que STACKLEAK no protege contra ataques similares realizados en una sola llamada al sistema.

Detección de desbordamiento de pila central en el núcleo


En el núcleo de vainilla (línea principal del núcleo de Linux), STACKLEAK es eficaz contra el desbordamiento de la profundidad de la pila del núcleo solo junto con CONFIG_THREAD_INFO_IN_TASK y CONFIG_VMAP_STACK. Ambas medidas son implementadas por Andy Lutomirski.

La versión más simple de explotar este tipo de vulnerabilidad se muestra en la Figura 5.



Esquema 5.

Sobrescribir ciertos campos en la estructura thread_info en la parte inferior de la pila nuclear puede aumentar los privilegios del proceso. Sin embargo, cuando la opción CONFIG_THREAD_INFO_IN_TASK está habilitada, esta estructura se elimina de la pila nuclear, lo que elimina el método descrito para explotar la vulnerabilidad.

Una versión más avanzada de este ataque es sobrescribir los datos en una región de memoria vecina saliendo del borde de la pila. Más sobre este enfoque:


Este tipo de ataque se refleja en la Figura 6.



Esquema 6.

La protección en este caso es CONFIG_VMAP_STACK. Cuando esta opción está habilitada, se coloca una página de memoria especial (página de protección) junto a la pila nuclear, cuyo acceso conduce a una excepción (Figura 7).



Esquema 7.

Finalmente, la opción más interesante de desbordar la pila en profundidad es un ataque como Stack Clash. La idea fue presentada por Gael Delalleau en 2005.

En 2017, los investigadores de la compañía Qualys lo repensaron, llamando a esta técnica Choque de pila. El hecho es que hay una manera de saltar sobre la página de protección y sobrescribir los datos de una región de memoria vecina (Figura 8). Esto se hace utilizando una matriz de longitud variable (VLA), cuyo tamaño es controlado por el atacante.



Esquema 8.

Para obtener más información sobre STACKLEAK y Stack Clash, consulte el blog de grsecurity .

¿Cómo protege STACKLEAK contra Stack Clash en la pila nuclear? Antes de cada llamada a alloca (), se realiza una verificación en profundidad del desbordamiento de la pila. Aquí está el código correspondiente de la versión 14 de la serie de parches:

void __used stackleak_check_alloca(unsigned long size) { unsigned long sp = (unsigned long)&sp; struct stack_info stack_info = {0}; unsigned long visit_mask = 0; unsigned long stack_left; BUG_ON(get_stack_info(&sp, current, &stack_info, &visit_mask)); stack_left = sp - (unsigned long)stack_info.begin; if (size >= stack_left) { /* * Kernel stack depth overflow is detected, let's report that. * If CONFIG_VMAP_STACK is enabled, we can safely use BUG(). * If CONFIG_VMAP_STACK is disabled, BUG() handling can corrupt * the neighbour memory. CONFIG_SCHED_STACK_END_CHECK calls * panic() in a similar situation, so let's do the same if that * option is on. Otherwise just use BUG() and hope for the best. */ #if !defined(CONFIG_VMAP_STACK) && defined(CONFIG_SCHED_STACK_END_CHECK) panic("alloca() over the kernel stack boundary\n"); #else BUG(); #endif } } 

Sin embargo, esta funcionalidad se excluyó de la versión 15. Esto se debió principalmente a la polémica prohibición de Linus Torvalds de usar BUG_ON () en parches de seguridad del kernel de Linux.

Además, la novena versión de la serie de parches condujo a una discusión, como resultado de lo cual se decidió eliminar todas las matrices variables del núcleo de la línea principal. Alrededor de 15 desarrolladores participaron en este trabajo, y se terminará pronto.

Impacto en el rendimiento de STACKLEAK


Doy los resultados de las pruebas de rendimiento en x86_64. Equipo: Intel Core i7-4770, 16 GB de RAM.

Prueba n. ° 1, atractiva: construir un kernel de Linux en un solo núcleo de procesador

  # time make   4.18: real 12m14.124s user 11m17.565s sys 1m6.943s   4.18+stackleak: real 12m20.335s (+0.85%) user 11m23.283s sys 1m8.221s 

Prueba n. ° 2, poco atractiva:

  # hackbench -s 4096 -l 2000 -g 15 -f 25 -P    4.18: 9.08     4.18+stackleak: 9.47  (+4.3%) 

Por lo tanto, el efecto de STACKLEAK en el rendimiento del sistema depende del tipo de carga. En particular, una gran cantidad de llamadas cortas al sistema aumentan los gastos generales. T.O. El rendimiento de STACKLEAK debe evaluarse para la carga planificada antes de la producción.

Dispositivo interno STACKLEAK


STACKLEAK consiste en:

  • El código que borra la pila del núcleo al final de la llamada al sistema (originalmente escrito en ensamblador),
  • Complemento GCC para compilación instrumental de código de kernel.

La eliminación de la pila del kernel se realiza en la función stackleak_erase (). Esta función se cumple antes de volver al espacio del usuario después de una llamada al sistema. STACKLEAK_POISON (-0xBEEF) se escribe en la parte utilizada de la pila de subprocesos. La variable lower_stack, constantemente actualizada en stackleak_track_stack (), apunta al punto de inicio de la limpieza.

Las etapas de stackleak_erase () se reflejan en los esquemas 9 y 10.



Esquema 9.



Esquema 10.

T.O. stackleak_erase () borra solo la parte utilizada de la pila nuclear. Es por eso que STACKLEAK es tan rápido. Y si borra los 16 kB de la pila del kernel en x86_64 al final de cada llamada al sistema, hackbench muestra una caída de rendimiento del 40%.

La instrumentación del código del núcleo en la etapa de compilación se realiza en el complemento STACKLEAK GCC.

Los complementos de GCC son módulos descargables específicos del proyecto para el compilador de GCC. Registran nuevos pases con el GCC Pass Manager, proporcionando devoluciones de llamada para estos pases.

Entonces, para la operación completa de STACKLEAK, las llamadas a stackleak_track_stack () se insertan en el código de funciones con un marco de pila grande (marco de pila). Además, antes de cada alloca (), se inserta una llamada al ya mencionado stackleak_check_alloca (), y después de eso, se inserta una llamada a stackleak_track_stack ().

Como ya se mencionó, en la versión 15 de la serie de parches, la inserción de llamadas a stackleak_check_alloca () se excluyó del complemento GCC.

Ruta en la línea principal del kernel de Linux


La ruta STACKLEAK en la línea principal es muy larga y difícil (Figura 11).



Esquema 11. Progreso en la implementación de STACKLEAK en la línea principal del kernel de Linux.

En abril de 2017, los creadores de grsecurity cerraron sus parches para la comunidad, comenzando a distribuirlos solo sobre una base comercial. En mayo de 2017, decidí asumir la tarea de introducir STACKLEAK en el núcleo de vainilla. Así comenzó un viaje de más de un año. La empresa Positive Technologies, en la que trabajo, me da la oportunidad de ocuparme de esta tarea durante parte de mi tiempo de trabajo. Pero básicamente, paso tiempo "libre" en ello.

Desde mayo pasado, mi serie de parches ha sufrido múltiples revisiones, ha sufrido cambios significativos, ha sido criticada dos veces por Linus Torvalds. Quería dejar todo esto muchas veces. Pero en cierto momento hubo un firme deseo de llegar al final. En el momento de la redacción (25 de septiembre de 2018), la decimoquinta versión de la serie de parches se encuentra en la rama Linux-next, cumple con todos los requisitos establecidos por Linus y está lista para la ventana de fusión del kernel 4.20 / 5.0.

Hace un mes, di una charla sobre este trabajo en la Cumbre de Seguridad de Linux. Proporciono enlaces a diapositivas y videos :


Conclusión


STACKLEAK es una característica de seguridad del kernel de Linux muy útil que bloquea la explotación de varios tipos de vulnerabilidades a la vez. Además, el autor original de PaX Team pudo hacerlo rápido y hermoso en ingeniería. Por lo tanto, la aparición de STACKLEAK en el kernel de vainilla sería valiosa para los usuarios de Linux con mayores requisitos de seguridad de la información. Además, trabajar en esta dirección llama la atención de la comunidad de desarrolladores de Linux sobre las herramientas de defensa personal del kernel.

PS


STACKLEAK fue finalmente adoptado por el núcleo Linux 4.20:
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2d6bb6adb714b133db92ccd4bfc9c20f75f71f3f

Las arquitecturas compatibles son x86_64, x86_32 y arm64.

Además, se ha completado el trabajo para eliminar las matrices de longitud variable del código del kernel de Linux. La advertencia del compilador Gcc "-Wvla" se incluye en la versión 4.20 del kernel: lkml.org/lkml/2018/10/28/189

Source: https://habr.com/ru/post/es424633/


All Articles