La plataforma utiliza traducción dinámica de código, en la que se van traduciendo los bloques de instrucciones a medida que es necesario ejecutarlas y las mete en una cache, de acuerdo al siguiente diagrama, de modo que los bloques de código sólo se traducen cuando van a ser ejecutados
Respecto a la protección, se obtiene por dos circunstancias:
- Por un lado, todo el código traducido tiene privilegios menores que los de la librería del sistema
- Por otro lado, todas las llamadas al sistema son chequeadas y traducidas dentro del entorno virtualizado
Respecto a la eficiencia de traducción, tras evaluar la posibilidad de tener una traducción a código intermedio que luego se optimiza, se decidieron por la estrategia más sencilla de tener una tabla de traducción para el código, que es simple y rápida.
Respecto a la eficiencia en la ejecución, el programa introduce optimizaciones en múltiples sentidos, como ejemplo se han contado algunas de las posibles implementaciones de las llamadas indirectas (ya que todas las instrucciones que afectan al flujo de control se tratan de manera especial), para intentar disminuir su peso (la traducción estándar requiere sustituir esa única llamada por treinta instrucciones):
- La implementación estática se traducen por una llamada con cache, de modo que se compara el destino con el anterior de esta misma llamada y si coincide no se ejecutan el resto de las comprobaciones, y su eficiencia depende de la tasa de aciertos.
- En las llamadas dinámicas, se utiliza una tabla de hash para las direcciones "permitidas", y si se encuentra en esa tabla, tampoco se hacen todas las comprobaciones
- Forzar la protección frente a ejecución en zonas de datos, como el heap o stack. Aunque los procesadores de Intel tienen esta funcionalidad, no todos los SO la tienen habilitada.
- Comprobar todas las cabeceras ELF.
- Proteger todas las estructuras de datos internas, utilizando mprotect para proteger todas las escrituras a memoria a las estructuras del entorno, salvo cuando se está ejecutando código de la propia máquina virtual.
- Interceptar todas las llamadas al sistema, tanto para permitirla, denegarla, devolver un valor artificial o traducirla a una llamada a código de usuario que haga lo que queramos. Por ejemplo, para hacer creer al código que tiene privilegios de root (de lo cual se incluía una demo).
Por último se ha presentado un estudio de las prestaciones del programa, y en media, la traducción introduce una ineficiencia de un 7%, que sólo sube a un 9% cuando se activan todas las medidas de protección de memoria y de filtrado de llamadas del sistema.
La librería se puede encontrar aquí.
No hay comentarios:
Publicar un comentario