stringtranslate.com

Seguridad de la memoria

La seguridad de la memoria es el estado de protección contra diversos errores de software y vulnerabilidades de seguridad cuando se trata de acceso a la memoria , como desbordamientos del búfer y punteros colgantes . [1] Por ejemplo, se dice que Java es seguro para la memoria porque su detección de errores en tiempo de ejecución verifica los límites de la matriz y las desreferencias de los punteros. [1] Por el contrario, C y C++ permiten aritmética de punteros arbitraria con punteros implementados como direcciones de memoria directa sin provisión para verificación de límites , [2] y por lo tanto son potencialmente inseguros para la memoria . [3]

Historia

Los errores de memoria se consideraron por primera vez en el contexto de la gestión de recursos (informática) y los sistemas de tiempo compartido , en un esfuerzo por evitar problemas como las bombas fork . [4] Los desarrollos fueron en su mayoría teóricos hasta que apareció el gusano Morris , que aprovechó un desbordamiento del buffer en fingerd . [5] El campo de la seguridad informática se desarrolló rápidamente a partir de entonces, intensificándose con multitud de nuevos ataques , como el ataque de retorno a libc y técnicas de defensa como la pila no ejecutable [6] y la aleatorización del diseño del espacio de direcciones . La aleatorización previene la mayoría de los ataques de desbordamiento del búfer y requiere que el atacante utilice la pulverización de montón u otros métodos dependientes de la aplicación para obtener direcciones, aunque su adopción ha sido lenta. [5] Sin embargo, las implementaciones de la tecnología generalmente se limitan a aleatorizar bibliotecas y la ubicación de la pila.

Impacto

En 2019, un ingeniero de seguridad de Microsoft informó que el 70% de todas las vulnerabilidades de seguridad fueron causadas por problemas de seguridad de la memoria. [7] En 2020, un equipo de Google informó de manera similar que el 70% de todos los "errores de seguridad graves" en Chromium fueron causados ​​por problemas de seguridad de la memoria. Muchas otras vulnerabilidades y exploits de alto perfil en software crítico se deben en última instancia a una falta de seguridad de la memoria, incluido Heartbleed [8] y un error de escalada de privilegios de larga data en sudo . [9] La omnipresencia y gravedad de las vulnerabilidades y exploits que surgen de problemas de seguridad de la memoria han llevado a varios investigadores de seguridad a describir la identificación de problemas de seguridad de la memoria como "cazar peces en un barril". [10]

Enfoques

La mayoría de los [ cita necesaria ] lenguajes de programación modernos de alto nivel son seguros para la memoria de forma predeterminada, aunque no del todo, ya que solo verifican su propio código y no el sistema con el que interactúan. La gestión automática de la memoria en forma de recolección de basura es la técnica más común para prevenir algunos de los problemas de seguridad de la memoria, ya que previene errores comunes de seguridad de la memoria, como el uso después de la liberación, para todos los datos asignados dentro del tiempo de ejecución del lenguaje. [11] Cuando se combinan con la verificación automática de límites en todos los accesos a la matriz y sin soporte para la aritmética de punteros sin formato, los lenguajes de recolección de basura brindan sólidas garantías de seguridad de la memoria (aunque las garantías pueden ser más débiles para operaciones de bajo nivel marcadas explícitamente como inseguras, como el uso de un interfaz de función externa ). Sin embargo, la sobrecarga de rendimiento de la recolección de basura hace que estos lenguajes no sean adecuados para determinadas aplicaciones críticas para el rendimiento. [1]

Para los lenguajes que utilizan administración de memoria manual , el tiempo de ejecución generalmente no garantiza la seguridad de la memoria. En cambio, las propiedades de seguridad de la memoria deben ser garantizadas por el compilador mediante un análisis estático del programa y una demostración automatizada de teoremas o deben ser administradas cuidadosamente por el programador en tiempo de ejecución. [11] Por ejemplo, el lenguaje de programación Rust implementa un verificador de préstamo para garantizar la seguridad de la memoria, [12] mientras que C y C++ no ofrecen garantías de seguridad de la memoria. La importante cantidad de software escrito en C y C++ ha motivado el desarrollo de herramientas externas de análisis estático como Coverity , que ofrece análisis de memoria estática para C. [13]

DieHard, [14] su rediseño DieHarder, [15] y Allinea Distributed Debugging Tool son asignadores de montón especiales que asignan objetos en su propia página de memoria virtual aleatoria, lo que permite detener y depurar lecturas y escrituras no válidas en la instrucción exacta que las causa. . La protección depende de la protección de la memoria del hardware y, por lo tanto, la sobrecarga no suele ser sustancial, aunque puede aumentar significativamente si el programa hace un uso intensivo de la asignación. [16] La aleatorización proporciona sólo protección probabilística contra errores de memoria, pero a menudo se puede implementar fácilmente en el software existente volviendo a vincular el binario.

La herramienta memcheck de Valgrind utiliza un simulador de conjunto de instrucciones y ejecuta el programa compilado en una máquina virtual de verificación de memoria, lo que proporciona una detección garantizada de un subconjunto de errores de memoria en tiempo de ejecución. Sin embargo, normalmente ralentiza el programa en un factor de 40, [17] y, además, se debe informar explícitamente sobre los asignadores de memoria personalizados. [18] [19]

Con acceso al código fuente, existen bibliotecas que recopilan y rastrean valores legítimos para punteros ("metadatos") y verifican la validez de cada acceso a puntero con los metadatos, como el recolector de basura Boehm . [20] En general, la seguridad de la memoria se puede garantizar de forma segura mediante la recolección de basura de seguimiento y la inserción de comprobaciones de tiempo de ejecución en cada acceso a la memoria; Este enfoque tiene gastos generales, pero menos que el de Valgrind. Todos los lenguajes de recolección de basura adoptan este enfoque. [1] Para C y C++, existen muchas herramientas que realizan una transformación del código en tiempo de compilación para realizar comprobaciones de seguridad de la memoria en tiempo de ejecución, como CheckPointer [21] y AddressSanitizer , que impone un factor de desaceleración promedio de 2. [22]

BoundWarden es un nuevo enfoque de aplicación de memoria espacial que utiliza una combinación de transformación en tiempo de compilación y técnicas de monitoreo concurrente en tiempo de ejecución. [23]

Tipos de errores de memoria

Pueden ocurrir muchos tipos diferentes de errores de memoria: [24] [25]

Referencias

  1. ^ abcd Dhurjati, Dinakar; Kowshik, Sumant; Adve, Vikram; Lattner, Chris (1 de enero de 2003). "Seguridad de la memoria sin comprobaciones de tiempo de ejecución ni recolección de basura" (PDF) . Actas de la conferencia ACM SIGPLAN de 2003 sobre lenguaje, compilador y herramienta para sistemas integrados . ACM. págs. 69–80. doi :10.1145/780732.780743. ISBN 1581136471. S2CID  1459540 . Consultado el 13 de marzo de 2017 .
  2. ^ Koenig, Andrés. "Cómo C dificulta la comprobación de los límites de la matriz". Dr. Dobb . Consultado el 13 de marzo de 2017 .
  3. ^ Akritidis, Periklis (junio de 2011). "Seguridad práctica de la memoria para C" (PDF) . Informe técnico - Universidad de Cambridge. Laboratorio de computación . Universidad de Cambridge, Laboratorio de Computación. ISSN  1476-2986. UCAM-CL-TR-798 . Consultado el 13 de marzo de 2017 .
  4. ^ Anderson, James P. "Estudio de planificación de seguridad informática" (PDF) . 2 . Centro de Sistemas Electrónicos . ESD-TR-73-51. {{cite journal}}: Citar diario requiere |journal=( ayuda )
  5. ^ ab van der Veen, Víctor; dutt-Sharma, nitish; Cavallaro, Lorenzo; Bos, Herbert (2012). "Errores de memoria: el pasado, el presente y el futuro" (PDF) . Investigación en Ataques, Intrusiones y Defensas . Apuntes de conferencias sobre informática. vol. 7462, págs. 86-106. doi :10.1007/978-3-642-33338-5_5. ISBN 978-3-642-33337-8. Consultado el 13 de marzo de 2017 .
  6. ^ Wojtczuk, Rafal. "Derrotar el parche de pila no ejecutable de Solar Designer". inseguro.org . Consultado el 13 de marzo de 2017 .
  7. ^ "Microsoft: el 70 por ciento de todos los errores de seguridad son problemas de seguridad de la memoria". ZDNET . Consultado el 21 de septiembre de 2022 .
  8. ^ "CVE-2014-0160". Vulnerabilidades y exposiciones comunes . Inglete. Archivado desde el original el 24 de enero de 2018 . Consultado el 8 de febrero de 2018 .
  9. ^ Goodin, Dan (4 de febrero de 2020). "El grave defecto que acechó en sudo durante 9 años otorga privilegios de root". Ars Técnica .
  10. ^ "Pescado en barril". fishinabarrel.github.io . Consultado el 21 de septiembre de 2022 .
  11. ^ ab Crichton, Will. "CS 242: Seguridad de la memoria". stanford-cs242.github.io . Consultado el 22 de septiembre de 2022 .
  12. ^ "Referencias". El Rustonomicón . Rust.org . Consultado el 13 de marzo de 2017 .
  13. ^ Bessey, Al; Engler, Dawson; Bloquear, Ken; Chelf, Ben; Chou, Andy; Fulton, Bryan; Hallem, Seth; Henri-Gros, Charles; Kamsky, Asya; McPeak, Scott (1 de febrero de 2010). "Unos miles de millones de líneas de código después". Comunicaciones de la ACM . 53 (2): 66–75. doi :10.1145/1646353.1646374. S2CID  2611544.
  14. ^ Berger, Emery D.; Zorn, Benjamin G. (1 de enero de 2006). "DieHard: seguridad de la memoria probabilística para lenguajes inseguros" (PDF) . Actas de la 27ª Conferencia ACM SIGPLAN sobre diseño e implementación de lenguajes de programación . ACM. págs. 158-168. doi :10.1145/1133981.1134000. ISBN 1595933204. S2CID  8984358 . Consultado el 14 de marzo de 2017 .
  15. ^ Novark, gen; Berger, Emery D. (1 de enero de 2010). "DieHarder: Asegurar el montón" (PDF) . Actas de la 17ª conferencia ACM sobre seguridad informática y de las comunicaciones . ACM. págs. 573–584. doi :10.1145/1866307.1866371. ISBN 9781450302456. S2CID  7880497 . Consultado el 14 de marzo de 2017 .
  16. ^ "Depuración de memoria en Allinea DDT". Archivado desde el original el 3 de febrero de 2015.
  17. ^ Gyllenhaal, Juan. "Uso de la herramienta Memcheck de Valgrind para encontrar fugas y errores de memoria". informática.llnl.gov . Archivado desde el original el 7 de noviembre de 2018 . Consultado el 13 de marzo de 2017 .
  18. ^ "Memcheck: un detector de errores de memoria". Manual de usuario de Valgrind . valgrind.org . Consultado el 13 de marzo de 2017 .
  19. ^ Kreinin, Yossi. "Por qué los asignadores/grupos personalizados son difíciles". Fijación adecuada . Consultado el 13 de marzo de 2017 .
  20. ^ "Uso del recolector de basura como detector de fugas". www.hboehm.info . Consultado el 14 de marzo de 2017 .
  21. ^ "Diseños semánticos: CheckPointer en comparación con otras herramientas de verificación de seguridad". www.semanticdesigns.com . Diseños semánticos, Inc.
  22. ^ "Números de rendimiento de AddressSanitizer". GitHub .
  23. ^ Dhumbumroong, Smith (2020). "BoundWarden: seguridad de la memoria espacial impuesta por subprocesos mediante transformaciones en tiempo de compilación". Ciencia de la programación informática . 198 : 102519. doi : 10.1016/j.scico.2020.102519. S2CID  224925197.
  24. ^ Gv, Naveen. "Cómo evitar, encontrar (y corregir) errores de memoria en su código C/C++". Cprogramming.com . Consultado el 13 de marzo de 2017 .
  25. ^ "CWE-633: Debilidades que afectan la memoria". Enumeración de debilidades comunitarias . INGLETA . Consultado el 13 de marzo de 2017 .
  26. ^ "CWE-762: Rutinas de gestión de memoria no coincidentes". Enumeración de debilidades comunitarias . INGLETA . Consultado el 13 de marzo de 2017 .