Subido por David Huaman Chavez

Articulo Spectre v2

Anuncio
Ataques Spectre: Explotación de la Ejecución
Especulativa
Paul Kocher1, Jann Horn2, Anders Fogh3, Daniel Genkin4,
Daniel Gruss5, Werner Haas6, Mike Hamburg7, Moritz Lipp5,
Stefan Mangard5, Thomas Prescher6, Michael Schwarz5, Yuval Yarom8
1 Independent
3G
(www.paulkocher.com), 2 Google Project Zero,
DATA Advanced Analytics, 4 University of Pennsylvania and University of Maryland,
5 Graz
7 Rambus,
University of Technology, 6 Cyberus Technology,
Cryptography Research Division, 8 University of Adelaide and Data61
Resumen
Los procesadores modernos utilizan la predicción y la ejecución especulativa para maximizar el
rendimiento. Por ejemplo, si el destino de una ejecución depende de un valor de memoria que está en
proceso de lectura, las CPU intentarán adivinar el destino e intentarán ejecutarlo con anticipación. Cuando
finalmente llega el valor de la memoria, la CPU descarta o confirma el cálculo especulativo. La lógica
especulativa es no confiable en cómo se ejecuta, ya que puede acceder a la memoria y los registros de la
víctima, y puede realizar operaciones con efectos secundarios medibles.
Los ataques de Spectre implican inducir a una víctima a realizar operaciones especulativas que no
ocurrirían durante la ejecución correcta del programa y que filtran la información confidencial de la
víctima a través de un canal lateral al adversario. Este documento describe los ataques prácticos que
combinan la metodología de los ataques de canal lateral, los ataques de fallas y la programación orientada
al retorno que puede reactivar la memoria arbitraria del proceso de la víctima. En términos más generales,
el documento muestra que las implementaciones de ejecución especulativa violan los supuestos de
seguridad que sustentan numerosos mecanismos de seguridad de software, incluida la separación de
procesos del sistema operativo, el uso de contenedores, la compilación justo a tiempo (JIT) y las
contramedidas para el tiempo de caché y los ataques de canal lateral. Estos ataques representan una seria
amenaza para los sistemas reales, ya que se encuentran capacidades de ejecución especulativa
vulnerables en microprocesadores de Intel, AMD y ARM que se utilizan en miles de millones de
dispositivos.
Si bien en algunos casos son posibles contramedidas improvisadas específicas sobre el procesador, las
soluciones requerirán correcciones a los diseños del procesador, así como actualizaciones a las
arquitecturas del conjunto de instrucciones (ISA) para dar a los arquitectos de hardware y desarrolladores
de software una comprensión común sobre que estado de implementaciones de computo de CPU son (y
cuáles no son) permitidas las fugas.
1. Introducción
Los cálculos realizados por dispositivos físicos a menudo dejan efectos secundarios observables más allá
de los resultados nominales del cálculo. Los ataques de canal lateral se centran en explotar estos efectos
secundarios para extraer información secreta que de otro modo no estaría disponible. Desde su
1
introducción a finales de los años 90 [43], muchos efectos físicos como el consumo de energía [41, 42], la
radiación electromagnética [58] o el ruido acústico [20] se han aprovechado para extraer claves
criptográficas, así como otros secretos.
Los ataques físicos de canal lateral también se pueden utilizar para extraer información secreta de
dispositivos complejos como PC y teléfonos móviles [21, 22]. Sin embargo, debido a que estos dispositivos
a menudo ejecutan código de un origen potencialmente desconocido, enfrentan amenazas adicionales en
forma de ataques basados en software, que no requieren equipos de medición externos. Mientras que
algunos ataques aprovechan las vulnerabilidades del software (como desbordamientos del búfer [5] o
errores de doble libre [12]), otros ataques de software aprovechan las vulnerabilidades del hardware para
filtrar información confidencial. Los ataques de este último tipo incluyen ataques de microarquitectura
que aprovechan el tiempo de caché [8, 30, 48, 52, 55, 69, 74], historial de predicción de bifurcacion [1, 2],
búferes de objetivo de bifurcacion [14, 44] o filas de DRAM abiertas [56 ] Las técnicas basadas en software
también se han utilizado para montar ataques de falla que alteran la memoria física [39] o los valores
internos de la CPU.
Varias técnicas de diseño microarquitectura han facilitado el aumento de la velocidad del procesador en
las últimas décadas. Uno de estos avances es la ejecución especulativa, que se usa ampliamente para
aumentar el rendimiento e implica que la CPU adivine las posibles direcciones de ejecución futuras y
ejecute prematuramente instrucciones en estos caminos. Más específicamente, considere un ejemplo en
el que el flujo de control del programa depende de un valor no almacenado en caché ubicado en la
memoria física externa. Como esta memoria es mucho más lenta que la CPU, a menudo toma varios
cientos de ciclos de reloj antes de que se conozca el valor. En lugar de desperdiciar estos ciclos al estar sin
uso, la CPU intenta adivinar la dirección del flujo de control, guarda un punto de control de su estado de
registro y procede a ejecutar especulativamente el programa en la ruta adivinada. Cuando el valor
finalmente llega de la memoria, la CPU verifica la exactitud de su suposición inicial. Si la suposición era
incorrecta, la CPU descarta la ejecución especulativa incorrecta al revertir el estado del registro al punto
de control almacenado, lo que resulta en un rendimiento comparable a la inactividad. Sin embargo, si la
suposición fue correcta, los resultados de la ejecución especulativa se comprometen, produciendo una
ganancia de rendimiento significativa ya que se realizó un trabajo útil durante el retraso.
Desde una perspectiva de seguridad, la ejecución especulativa implica ejecutar un programa de formas
posiblemente incorrectas. Sin embargo, debido a que las CPU están diseñadas para mantener la
corrección funcional al revertir los resultados de ejecuciones especulativas incorrectas a sus estados
anteriores, se suponía anteriormente que estos errores eran seguros.
1.1 Nuestros resultados
En este artículo, analizamos las implicaciones de seguridad de tal ejecución especulativa incorrecta.
Presentamos una clase de ataques microarquitectónicos que llamamos ataques Spectre. A un alto nivel,
los ataques de Spectre engañan al procesador para que ejecute secuencias de instrucciones especulativas
que no deberían haberse ejecutado con la ejecución correcta del programa. Como los efectos de estas
instrucciones en el estado nominal de la CPU se revierten, los llamamos instrucciones transitorias. Al
influir en qué instrucciones transitorias se ejecutan especulativamente, podemos filtrar información
desde el espacio de direcciones de memoria de la víctima.
Demostramos empíricamente la viabilidad de los ataques de Spectre mediante la explotación de
secuencias de instrucciones transitorias para filtrar información a través de dominios de seguridad tanto
del código nativo no privilegiado como del código JavaScript portátil
Ataques con código nativo. Como prueba de concepto, creamos un programa simple para víctimas que
contiene datos secretos dentro de su espacio de direcciones de memoria. A continuación, buscamos en
el binario compilado de la víctima y en las bibliotecas compartidas del sistema operativo secuencias de
2
instrucciones que se pueden usar para filtrar información del espacio de direcciones de la víctima.
Finalmente, escribimos un programa atacante que explota la función de ejecución especulativa de la CPU
para ejecutar las secuencias encontradas previamente como instrucciones transitorias. Con esta técnica,
podemos leer la memoria del espacio de direcciones de la víctima, incluidos los secretos almacenados en
ella.
Ataques con JavaScript y eBPF. Además de violar los límites de aislamiento del proceso usando código
nativo, los ataques Spectre también se pueden usar para violar el área de prueba, por ejemplo,
montándolos a través de un código JavaScript portátil. Demostrando esto empíricamente, mostramos un
programa JavaScript que lee con éxito los datos del espacio de direcciones del proceso del navegador que
lo ejecuta. Además, demostramos ataques aprovechando el intérprete eBPF y JIT en Linux
1.2 Nuestras técnicas
En un nivel alto, los ataques de Spectre violan los límites de aislamiento de la memoria al combinar la
ejecución especulativa con la exfiltración de datos a través de canales encubiertos microarquitectónicos.
Más específicamente, para montar un ataque Spectre, un atacante comienza localizando o introduciendo
una secuencia de instrucciones dentro del espacio de direcciones del proceso que, cuando se ejecuta,
actúa como un transmisor de canal secreto que pierde la memoria de la víctima o registra el contenido.
Luego, el atacante engaña a la CPU para que ejecute especulativamente y erróneamente esta secuencia
de instrucciones, filtrando así la información de la víctima por el canal secreto. Finalmente, el atacante
recupera la información de la víctima a través del canal secreto. Si bien los cambios en el estado nominal
de la CPU como resultado de esta ejecución especulativa errónea se revierten eventualmente, la
información previamente filtrada o los cambios en otros estados microarquitectónicos de la CPU, por
ejemplo, el contenido de la memoria caché, pueden sobrevivir a la reversión del estado nominal.
La descripción anterior de los ataques de Spectre es general, y necesita ser instanciada concretamente
con una forma de inducir la ejecución especulativa errónea, así como con un canal secreto
microarquitectónico. Si bien son posibles muchas opciones para el componente de canal secreto, las
implementaciones descritas en este trabajo utilizan canales secretos basados en caché [64], es decir, Flush
+ Reload [74] y Evict + Reload [25, 45].
Ahora procedemos a describir nuestras técnicas para inducir e influir en la ejecución especulativa errónea.
Variante 1: Explotación de bifurcaciones condicionales.
En esta variante de los ataques de Spectre, el atacante entrena mal al predictor de bifurcación de la CPU
para predecir erróneamente la dirección de una bifurcación, lo que hace que la CPU viole temporalmente
la semántica del programa al ejecutar código que de otro modo no se habría ejecutado. Como mostramos,
esta ejecución especulativa incorrecta permite a un atacante leer información secreta almacenada en el
espacio de direcciones del programa. De hecho, considere el siguiente ejemplo de código:
if (x < array1_size)
y = array2[array1[x] * 4096];
En el ejemplo anterior, suponga que la variable x contiene datos controlados por el atacante. Para
garantizar la validez del acceso a la memoria de array1, el código anterior contiene una declaración if cuyo
propósito es verificar que el valor de x esté dentro de un rango legal. Mostramos cómo un atacante puede
omitir esta declaración if, leyendo así datos potencialmente secretos del espacio de direcciones del
proceso.
Primero, durante una fase inicial de entrenamiento incorrecto, el atacante invoca el código anterior con
entradas válidas, entrenando así al predictor de bifurcacion para que espere que el if sea verdadero.
Luego, durante la fase de explotación, el atacante invoca el código con un valor de x fuera de los límites
de array1. En lugar de esperar la determinación del resultado de la bifurcacion, la CPU adivina que la
verificación de límites será verdadera y ya ejecuta especulativamente instrucciones que evalúan array2
3
[array1 [x] * 4096] utilizando la x maliciosa. Tenga en cuenta que la lectura de array2 carga datos en el
caché en una dirección que depende de array1 [x] usando la x maliciosa, escalada para que los accesos
vayan a diferentes líneas de caché y para evitar efectos de captación previa de hardware.
Cuando finalmente se determina el resultado de la verificación de límites, la CPU descubre su error y
revierte cualquier cambio realizado a su estado microarquitectura nominal. Sin embargo, los cambios
realizados en el estado de la memoria caché no se revierten, por lo que el atacante puede analizar el
contenido de la memoria caché y encontrar el valor del byte potencialmente secreto recuperado en la
lectura fuera de los límites de la memoria de la víctima.
Variante 2: Explotación de bifurcaciones indirectas.
A partir de la programación orientada al retorno (ROP) [63], en esta variante el atacante elige un
dispositivo del espacio de direcciones de la víctima e influye en la víctima para que ejecute el dispositivo
de forma especulativa. A diferencia de ROP, el atacante no se basa en una vulnerabilidad en el código de
la víctima. En su lugar, el atacante entrena el Branch Target Buffer (BTB) para predecir erróneamente una
bifurcacion de una instrucción indirecta de bifurcación a la dirección del dispositivo, lo que resulta en la
ejecución especulativa del dispositivo. Como antes, si bien los efectos de la ejecución especulativa
incorrecta en el estado nominal de la CPU finalmente se revierten, sus efectos en el caché no lo son, lo
que permite que el dispositivo filtre información confidencial a través de un canal lateral de caché.
Demostramos esto empíricamente y mostramos cómo la selección cuidadosa de dispositivos permite que
este método lea la memoria arbitraria de la víctima
Para forzar el BTB, el atacante encuentra la dirección virtual del gadget en el espacio de direcciones de la
víctima, luego realiza ramificaciones indirectas a esta dirección. Este entrenamiento se realiza desde el
espacio de direcciones del atacante. No importa qué reside en la dirección del gadget en el espacio de
direcciones del atacante; todo lo que se requiere es que las direcciones virtuales del atacante durante el
entrenamiento coincidan (o alias con) las de la víctima. De hecho, siempre que el atacante maneje las
excepciones, el ataque puede funcionar incluso si no hay un código asignado en la dirección virtual del
gadget en el espacio de direcciones del atacante.
Otras variantes. Se pueden diseñar más ataques variando tanto el método para lograr la ejecución
especulativa como el método utilizado para filtrar la información. Los ejemplos incluyen instrucciones de
devolución mal formadas, información de fugas a través de variaciones de tiempo y contención en
unidades aritméticas
1.3. Hardware objetivo y Estado Actual
Hardware. Hemos verificado empíricamente la vulnerabilidad de varios procesadores Intel a los ataques
de Spectre, incluidos los procesadores Ivy Bridge, Haswell, Broadwell, Skylake y Kaby Lake. También
hemos verificado la aplicabilidad del ataque a las CPU AMD Ryzen. Finalmente, también hemos montado
con éxito los ataques Specter en varios procesadores Samsung y Qualcomm basados en ARM que se
encuentran en teléfonos móviles populares.
Estado Actual. Utilizando la práctica de la divulgación responsable, grupos disjuntos de autores de este
documento proporcionaron versiones preliminares de nuestros resultados a grupos de proveedores de
CPU y otras compañías afectadas que se superponen parcialmente. En coordinación con la industria, los
autores también participaron en una difusion de los resultados. La familia de ataques Spectre está
documentada bajo CVE-2017-5753 y CVE-2017-5715.
1.4. Meltdown
Meltdown [47] es un ataque microarquitectural relacionado que explota la ejecución fuera de orden para
perder la memoria del núcleo. Meltdown es distinto de los ataques de Spectre en dos formas principales.
4
Primero, a diferencia de Spectre, Meltdown no usa predicción de bifurcación. En cambio, se basa en la
observación de que cuando una instrucción causa una trampa, las instrucciones siguientes se ejecutan
fuera de orden antes de ser terminadas. En segundo lugar, Meltdown explota una vulnerabilidad
específica para muchos procesadores Intel y algunos procesadores ARM que permite que ciertas
instrucciones ejecutadas especulativamente eviten la protección de la memoria. Combinando estos
problemas, Meltdown accede a la memoria del núcleo desde el espacio del usuario. Este acceso provoca
una trampa, pero antes de que se emita la trampa, las instrucciones que siguen al acceso filtran el
contenido de la memoria accedida a través de un canal oculto de caché. En contraste, Specter ataca a una
gama más amplia de procesadores, incluida la mayoría de los procesadores AMD y ARM. Además, el
mecanismo KAISER [29], que se ha aplicado ampliamente como mitigación del ataque Meltdown, no
protege contra Spectre.
2. Antecedentes
En esta sección, describimos algunos de los componentes microarquitectónicos de los procesadores
modernos de alta velocidad, cómo mejoran el rendimiento y cómo pueden filtrar información de los
programas en ejecución. También describimos la programación orientada al retorno (ROP) y los gadgets.
2.1. Ejecución fuera de orden.
Un paradigma de ejecución fuera de orden aumenta la utilización de los componentes del procesador al
permitir que las instrucciones más abajo en el flujo de instrucciones de un programa se ejecuten en
paralelo y, a veces, antes de las instrucciones anteriores. Los procesadores modernos trabajan
internamente con microoperaciones, emulando el conjunto de instrucciones de la arquitectura, es decir,
las instrucciones se descodifican en microoperaciones [15]. Una vez que se han completado todos los
microops correspondientes a una instrucción, así como todas las instrucciones anteriores, las
instrucciones pueden retirarse, confirmando sus cambios en los registros y otros estados arquitectónicos
y liberando el espacio de almacenamiento intermedio de reordenamiento. Como resultado, las
instrucciones se retiran en orden de ejecución del programa.
2.2. Ejecución especulativa.
A menudo, el procesador no conoce el flujo de instrucciones futuro de un programa. Por ejemplo, esto
ocurre cuando la ejecución fuera de orden alcanza una instrucción de bifurcación condicional cuya
dirección depende de instrucciones anteriores cuya ejecución aún no se ha completado. En tales casos, el
procesador puede preservar su estado de registro actual, hacer una predicción sobre la ruta que seguirá
el programa y ejecutar instrucciones especulativas a lo largo de la ruta. Si la predicción resulta ser correcta,
los resultados de la ejecución especulativa se confirman (es decir, se guardan), lo que proporciona una
ventaja de rendimiento sobre el ralentí durante la espera. De lo contrario, cuando el procesador
determina que siguió el camino incorrecto, abandona el trabajo que realizó especulativamente al revertir
su estado de registro y reanudar a lo largo del camino correcto. Nos referimos a instrucciones que se
realizan erróneamente (es decir, como resultado de una predicción errónea), pero pueden dejar rastros
microarquitectónicos, como instrucciones transitorias. Aunque la ejecución especulativa mantiene el
estado arquitectónico del programa como si la ejecución siguiera el camino correcto, los elementos
microarquitectónicos pueden estar en un estado diferente (pero válido) que antes de la ejecución
transitoria. La ejecución especulativa en CPU modernas puede ejecutar varios cientos de instrucciones
por delante. El límite generalmente se rige por el tamaño del búfer de reordenamiento en la CPU. Por
ejemplo, en la microarquitectura de Haswell, el búfer de reordenamiento tiene espacio suficiente para
5
192 microoperaciones [15]. Como no existe una relación uno a uno entre el número de microoperaciones
e instrucciones, el límite depende de las instrucciones que se utilicen.
2.3. Predicción de bifurcación.
Durante la ejecución especulativa, el procesador adivina el resultado probable de las instrucciones de
bifurcación. Las mejores predicciones mejoran el rendimiento al aumentar el número de operaciones
ejecutadas especulativamente que pueden confirmarse con éxito.
Los predictores de bifurcación de los procesadores Intel modernos, por ejemplo, los procesadores Haswell
Xeon, tienen múltiples mecanismos de predicción para bifurcaciones directas e indirectas. Las
instrucciones de ramificación indirecta pueden saltar a direcciones de destino arbitrarias calculadas en
tiempo de ejecución. Por ejemplo, las instrucciones x86 pueden saltar a una dirección en un registro,
ubicación de memoria o en la pila, por ejemplo, "jmp eax "," jmp [eax] "y" ret ". Las bifurcaciones
indirectas también son compatibles con ARM (por ejemplo, "MOV pc, r14"), MIPS (por ejemplo, "jr $ ra"),
RISC-V (por ejemplo, "jalr x0, x1,0") y otros procesadores. Para compensar la flexibilidad adicional en
comparación con las bifurcaciones directas, los saltos indirectos y las llamadas se optimizan utilizando al
menos dos mecanismos de predicción diferentes [35].
Intel [35] describe que el procesador predice:
 “Llamadas y saltos directos” de manera estática o monotónica
 “Llamadas y saltos indirectos” de manera monotónica o de manera variable, que depende del
comportamiento reciente del programa, y para
 “bifurcaciones condicionales”, el objetivo de la bifurcación y si se tomará la bifurcación.
En consecuencia, se utilizan varios componentes del procesador para predecir el resultado de las
bifurcaciones. El Branch Target Buffer (BTB) mantiene una asignación de direcciones de instrucciones de
bifurcación ejecutadas recientemente a direcciones de destino [44]. Los procesadores pueden usar el BTB
para predecir futuras direcciones de código incluso antes de decodificar las instrucciones de bifurcación.
Evtyushkin et al. [14] analizó el BTB de un procesador Intel Haswell y concluyó que solo los 31 bits menos
significativos de la dirección de la sucursal se utilizan para indexar el BTB. Para las bifurcaciones
condicionales, no es necesario registrar la dirección de destino para predecir el resultado de la bifurcación,
ya que el destino generalmente se codifica en la instrucción mientras la condición se determina en tiempo
de ejecución. Para mejorar las predicciones, el procesador mantiene un registro de los resultados de las
bifurcaciones, tanto para las bifurcaciones directas como indirectas recientes. Bhattacharya et al. [9]
analizó la estructura de predicción del historial de sucursales en procesadores Intel recientes. Aunque las
instrucciones de retorno son un tipo de bifurcación indirecta, a menudo se usa un mecanismo separado
para predecir la dirección de destino en las CPU modernas. El Buffer de Pila de Devolución (RSB) mantiene
una copia de la porción utilizada más recientemente de la pila de llamadas [15]. Si no hay datos disponibles
en el RSB, diferentes procesadores detendrán la ejecución o utilizarán el BTB como respaldo [15]. La lógica
de predicción de bifurcación, por ejemplo, BTB y RSB, generalmente no se comparte entre los núcleos
físicos [19]. Por lo tanto, el procesador aprende solo de las bifurcaciones anteriores ejecutadas en el
mismo núcleo.
2.4. La jerarquía de la memoria.
Para cerrar la brecha de velocidad entre el procesador más rápido y la memoria más lenta, los
procesadores usan una jerarquía de cachés sucesivamente más pequeños pero más rápidos. Los cachés
dividen la memoria en fragmentos de tamaño fijo llamados líneas, con tamaños de línea típicos de 64 o
128 bytes. Cuando el procesador necesita datos de la memoria, primero verifica si el caché L1, en la parte
superior de la jerarquía, contiene una copia. En el caso de un acierto en la memoria caché, es decir, los
6
datos se encuentran en la memoria caché, los datos se recuperan de la memoria caché L1 y se utilizan. De
lo contrario, en el caso de una falta de memoria caché, el procedimiento se repite para intentar recuperar
los datos de los siguientes niveles de memoria caché y, finalmente, la memoria externa. Una vez que se
completa una lectura, los datos generalmente se almacenan en la memoria caché (y se desaloja un valor
previamente almacenado en caché para hacer espacio) en caso de que se necesite nuevamente en el
futuro cercano. Procesadores Intel modernos típicamente tienen tres niveles de caché, cada núcleo tiene
cachés L1 y L2 dedicados y todos los núcleos comparten un caché L3 común, también conocido como
caché de último nivel (LLC). Un procesador debe asegurarse de que los cachés L1 y L2 por núcleo sean
coherentes utilizando un protocolo de coherencia de caché, a menudo basado en el protocolo MESI [35].
En particular, el uso del protocolo MESI o algunas de sus variantes implica que una operación de escritura
de memoria en un núcleo hará que las copias de los mismos datos en los cachés L1 y L2 de otros núcleos
se marquen como no válidos, lo que significa que los futuros accesos a estos datos en otros núcleos no
podrán cargar rápidamente los datos del caché L1 o L2 [53, 68]. Cuando esto sucede repetidamente en
una ubicación de memoria específica, esto se denomina informalmente rebote de línea de caché. Debido
a que la memoria se almacena en caché con una granularidad de línea, esto puede suceder incluso si dos
núcleos acceden a diferentes ubicaciones de memoria cercanas que se asignan a la misma línea de caché.
Este comportamiento se denomina intercambio falso y es conocido como una fuente de problemas de
rendimiento [33]. Estas propiedades del protocolo de coherencia de caché a veces se pueden abusar como
un reemplazo para el desalojo de caché utilizando la instrucción clflush o patrones de desalojo [27]. Este
comportamiento fue previamente explorado como un mecanismo potencial para facilitar los ataques de
Rowhammer [16].
2.5. Ataques de canal lateral microarquitectónicos
Todos los componentes de microarquitectura que discutimos anteriormente mejoran el rendimiento del
procesador al predecir el comportamiento futuro del programa. Con ese objetivo, mantienen un estado
que depende del comportamiento del programa pasado y asumen que el comportamiento futuro es
similar o relacionado con el comportamiento pasado. Cuando varios programas se ejecutan en el mismo
hardware, ya sea simultáneamente o por tiempo compartido, los cambios en el estado microarquitectura
causado por el comportamiento de un programa pueden afectar a otros programas. Esto, a su vez, puede
dar lugar a filtraciones involuntarias de información de un programa a otro [19]. Los ataques iniciales del
canal lateral microarquitectónico explotaron la variabilidad del tiempo [43] y la fuga a través del caché de
datos L1 para extraer claves de primitivas criptográficas [52, 55, 69]. A lo largo de los años, se han
demostrado canales en múltiples componentes microarquitectónicos, incluidos el caché de instrucciones
[3], los cachés de nivel inferior [30, 38, 48, 74], el BTB [14, 44] y el historial de ramificaciones [1, 2] . Los
objetivos de los ataques se han ampliado para abarcar la detección de ubicación conjunta [59], la ruptura
de ASLR [14, 26, 72], el control de pulsaciones de teclas [25], la impresión de dedos en el sitio web [51] y
el procesamiento del genoma [10]. Los resultados recientes incluyen ataques entre núcleos y CPU
cruzados [37, 75], ataques basados en la nube [32, 76], ataques en y desde entornos de ejecución
confiables [10, 44, 61], ataques desde código móvil [23, 46 , 51], y nuevas técnicas de ataque [11, 28, 44].
En este trabajo, utilizamos la técnica Flush + Reload [30, 74], y su variante Evict + Reload [25], para filtrar
información confidencial. Usando estas técnicas, el atacante comienza desalojando a una línea de caché
que comparte con la víctima. Después de que la víctima ejecuta durante un tiempo, el atacante mide el
tiempo que lleva realizar una lectura de memoria en la dirección correspondiente a la línea de caché
desalojada. Si la víctima accedió a la línea de caché monitoreada, los datos estarán en el caché y el acceso
será rápido. De lo contrario, si la víctima no ha accedido a la línea, la lectura será lenta. Por lo tanto, al
medir el tiempo de acceso, el atacante aprende si la víctima accedió a la línea de caché monitoreada entre
los pasos de desalojo y sondeo. La principal diferencia entre las dos técnicas es el mecanismo utilizado
7
para desalojar la línea de caché monitoreada de la caché. En la técnica Flush + Reload, el atacante usa una
instrucción de máquina dedicada, por ejemplo, clflush de x86, para desalojar la línea. Usando Evict +
Reload, el desalojo se logra forzando la contención en el conjunto de caché que almacena la línea, por
ejemplo, accediendo a otras ubicaciones de memoria que se cargan en el caché y (debido al tamaño
limitado del caché) hace que el procesador descarte ( desalojar) la línea que se sondea posteriormente.
2.6. Programación orientada al retorno
La programación orientada al retorno (ROP) [63] es una técnica que permite a un atacante que secuestra
el flujo de control hacer que una víctima realice operaciones complejas encadenando fragmentos de
código de máquina, llamados gadgets, que se encuentran en el código del víctima vulnerable Más
específicamente, el atacante primero encuentra artilugios utilizables en el binario de la víctima. Cada
gadget realiza algunos cálculos antes de ejecutar una instrucción de devolución. Un atacante que puede
modificar el puntero de la pila, por ejemplo, para apuntar para devolver direcciones escritas en un búfer
de escritura externa, o sobrescribir el contenido de la pila, por ejemplo, usando un desbordamiento de
búfer, puede hacer que el puntero de la pila apunte al comienzo de una serie de Direcciones de gadget
elegidas de forma malintencionada. Cuando se ejecuta, cada instrucción de retorno salta a una dirección
de destino desde la pila. Debido a que el atacante controla esta serie de direcciones, cada retorno salta
efectivamente al siguiente gadget de la cadena.
8
Descargar