Solución alternativa para la advertencia de Spectre MSVC C5040

6 minutos de lectura

avatar de usuario
HostileFork dice que no confíes en SE

MSVC acaba de publicar una actualización que ha agregado una nueva advertencia sobre algún código que el compilador inyectará para mitigar (aparentemente un poco) de Spectre:

https://blogs.msdn.microsoft.com/vcblog/2018/01/15/spectre-mitigations-in-msvc/

Aquí hay un pequeño MCVE derivado de su ejemplo de código “problemático”:

#include <stdio.h>

int main(int argc, char *argv) {
    unsigned char array1[1] = {0};
    int array1_length = 1;
    unsigned char array2[1] = {99};
    int untrusted_index = 0; /* in this MCVE, I trust it, compiler doesn't */
    for (; untrusted_index < array1_length; ++untrusted_index) {
        unsigned char value = array1[untrusted_index];
        unsigned char value2 = array2[value * 64];
        printf("Picked value %d\n", value2);
    }
    return 0;
}

“En el ejemplo anterior, el código realiza una verificación de los límites de la matriz para asegurarse de que untrusted_index sea menor que la longitud de la matriz1. Esto es necesario para garantizar que el programa no lea más allá de los límites de la matriz. Si bien esto parece correcto tal como está escrito, no tiene en cuenta los comportamientos microarquitectónicos de la CPU que implican una ejecución especulativa”.

Así que ahora recibes una advertencia:

Advertencia C5045: El compilador insertará la mitigación de Spectre para la carga de memoria si se especifica el modificador /Qspectre

Que es su forma de decirle que este código podría terminar siendo más lento de lo que le gustaría que fuera (si se compila /Qspectre), porque va a incluir algunas protecciones adicionales.

Dado que no parece que puedas dar nada por sentado, sospecho de hacer cambios que “solo haz que desaparezca la advertencia”. Por ejemplo, cambiando untrusted_index < array1_length a untrusted_index != array1_length parece hacerlo, para la instancia específica del código MCVE que doy aquí. Pero, ¿es ese un parche viable, o su advertencia es simplemente incompleta, y en la próxima actualización, también se quejará de eso?

Sé que puedo deshabilitar la advertencia con /wd5040 o de otra manera. Pero estoy interesado en asegurarme de que si el código se compila con /Qspectre, no haya ralentizaciones y que no haya advertencias si no se compila con /Qspectre. No quiero andar tocando archivos cambiando < a != en condiciones de bucle, o lo que sea, si eso es solo rotación.

Entonces, una pregunta más importante sería si hay patrones de solución legítimos que son tan básicos, ¿por qué no hay algunas menciones de ellos? Por ejemplo, el caso que describo es una iteración en la que controlo el índice y no tengo que preocuparme de que provenga de una “fuente no confiable”. Sin embargo, recibí una advertencia y cambié de < a != hizo que se fuera. ¿Por qué? debería tener?

  • Su ejemplo está roto con respecto al problema de Spectre: no hay verificación de límites antes de acceder a la matriz. Siga con el ejemplo proporcionado en el artículo citado.

    – Yann Droneaud

    17 mayo 2018 a las 20:32

  • @YannDroneaud No. (a) de qué estás hablando, hay una verificación de límites. (b) Si “me quedo con el ejemplo en el artículo citado”, no sería un MCVE, no podría copiarse, pegarse y compilarse para mostrar la advertencia, luego modificarse como se indica para mostrar que desaparece.

    – HostileFork dice que no confíes en SE

    17 mayo 2018 a las 20:36

  • De todos modos, creo que debería usar /Qspectre de forma predeterminada, solo para no tener que revisar toda su base de código en busca de ubicaciones que requieran una ejecución especulativa para ser derrotada para evitar la vulnerabilidad de la variante #1 de Spectre.

    – Yann Droneaud

    17 mayo 2018 a las 20:36

  • @YannDroneaud La pregunta no es “es/Qspectre bueno” o “debería usar/Qspectre”.

    – HostileFork dice que no confíes en SE

    17 mayo 2018 a las 20:38


  • Me pregunto si “el código realiza una verificación de los límites de la matriz para asegurarse de que untrusted_index sea menor que la longitud de la matriz1” es más como “… dentro de la matriz? En mi opinión, los problemas deberían desaparecer si ambos array1_length, untrusted_index son enteros sin signo aquí. Sugerir size_t.

    – chux – Reincorporar a Monica

    17 mayo 2018 a las 22:24


Del propio artículo:

Es importante tener en cuenta que existen límites para el análisis que MSVC y los compiladores en general pueden realizar cuando intentan identificar instancias de la variante 1. Como tal, no hay garantía de que todas las instancias posibles de la variante 1 se instrumenten en /Qspectre.

Probablemente haya encontrado uno de los casos en los que la implementación actual de /Qspectre no mitigará la vulnerabilidad por diseño. Esto es razonable porque el uso excesivo de LFENCE puede reducir significativamente el rendimiento. Mitigar cada instancia individual de la variante 1 que aparece en el código es demasiado costoso para hacerlo completamente en software (usando LFENCE).

En los comentarios, alguien preguntó:

¿Puede describir a los desarrolladores cuáles son los límites de MSVC y qué deben hacer más desarrolladores para protegerse de la “variante 1”?

El autor del artículo respondió:

No vamos a entrar en los detalles de la implementación de MSVC. Muchas personas y empresas confían en nuestras herramientas, por lo que vamos a pecar de precavidos con respecto a lo que discutimos públicamente.

Por lo tanto, Microsoft no parece querer revelar exactamente qué instancias de la variante 1 no serán mitigadas por /Qspectre.

Si no desea la advertencia, use la advertencia #pragma (deshabilitar: 5040) o desactívela en la página de propiedades del proyecto.

Y tenga en cuenta que su cambio ofrecido a “untrusted_index != array1_length” no es suficiente, ya que deja todo el rango mayor que el tamaño abierto al abuso.

Recuerde, este diagnóstico simplemente le dice que el compilador haría algo diferente que antes con la mitigación de espectro habilitada, en realidad no le dice que necesariamente debe hacer cualquier cosa al código.

  • “Y tenga en cuenta que su cambio ofrecido a” untrusted_index != array1_length “no es suficiente, ya que deja todo el rango mayor que el tamaño abierto al abuso”. Mi ejemplo es específicamente sobre las iteraciones de bucle de esta categoría, donde controlo el índice… y no quiero el código de mitigación si Qspectre está habilitado (o la advertencia si no lo está). Entonces, ¿de qué se trata exactamente != que hace que la advertencia no se active.

    – HostileFork dice que no confíes en SE

    17 mayo 2018 a las 21:35

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad