Seguridad de la memoria

Estado de estar protegido contra errores de acceso a la memoria

La seguridad de la memoria es el estado de estar protegido de varios errores de software y vulnerabilidades de seguridad cuando se trata del acceso a la memoria , como desbordamientos de 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 punteros. [1] Por el contrario, C y C++ permiten una aritmética de punteros arbitraria con punteros implementados como direcciones de memoria directa sin ninguna disposición para la 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 de bifurcación . [4] Los desarrollos fueron principalmente teóricos hasta el gusano Morris , que explotó un desbordamiento de búfer en fingerd . [5] El campo de la seguridad informática se desarrolló rápidamente a partir de entonces, escalando 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 evita la mayoría de los ataques de desbordamiento de búfer y requiere que el atacante use 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 las 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 se debían a 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 se debían a problemas de seguridad de la memoria. Muchas otras vulnerabilidades y exploits de alto perfil en software crítico se han derivado en última instancia de 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 la 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 "disparar a peces en un barril". [10]

Aproches

Algunos lenguajes de programación de alto nivel modernos son seguros para la memoria por defecto [ cita requerida ] , aunque no completamente ya que solo verifican su propio código y no el sistema con el que interactúan. La gestión automática de 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 memoria, ya que evita errores comunes de seguridad de memoria como el uso después de la liberación para todos los datos asignados dentro del entorno de ejecución del lenguaje. [11] Cuando se combinan con la verificación automática de límites en todos los accesos a matrices y sin soporte para aritmética de punteros sin formato , los lenguajes con recolección de basura brindan fuertes garantías de seguridad de memoria (aunque las garantías pueden ser más débiles para operaciones de bajo nivel marcadas explícitamente como no seguras, como el uso de una 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 ciertas aplicaciones de rendimiento crítico. [1]

En el caso de los lenguajes que utilizan la gestión manual de memoria , la seguridad de la memoria no suele estar garantizada por el entorno de ejecución. En cambio, las propiedades de seguridad de la memoria deben ser garantizadas por el compilador a través del análisis estático del programa y la demostración automatizada de teoremas o gestionadas cuidadosamente por el programador en el entorno de ejecución. [11] Por ejemplo, el lenguaje de programación Rust implementa un verificador de préstamos 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 de análisis estático externo como Coverity , que ofrece análisis de memoria estática para C. [13]

DieHard, [14] su rediseño DieHarder, [15] y la herramienta de depuración distribuida Allinea 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 se basa en la protección de la memoria del hardware y, por lo tanto, la sobrecarga normalmente no es sustancial, aunque puede crecer significativamente si el programa hace un uso intensivo de la asignación. [16] La aleatorización proporciona solo protección probabilística contra errores de memoria, pero a menudo se puede implementar fácilmente en el software existente al volver 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 garantiza la detección 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, debe recibir información explícita 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 cada acceso de puntero contra los metadatos para su validez, como el recolector de basura Boehm . [20] En general, la seguridad de la memoria se puede garantizar de manera segura mediante el rastreo de la recolección de basura y la inserción de comprobaciones en tiempo de ejecución en cada acceso a la memoria; este enfoque tiene una sobrecarga, pero menor que la 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 en tiempo de compilación del código para realizar comprobaciones de seguridad de 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]

Las pruebas fuzz son adecuadas para encontrar errores de seguridad de la memoria y a menudo se utilizan en combinación con verificadores dinámicos como AddressSanitizer.

Clasificación de errores de seguridad de la memoria

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

  • Espacial
  • Temporal
    • Uso después de la liberación : desreferenciar un puntero colgante que almacena la dirección de un objeto que ha sido eliminado.
    • Doble liberación : las llamadas repetidas a free pueden liberar prematuramente un nuevo objeto en la misma dirección. Si no se ha reutilizado la dirección exacta, pueden producirse otros daños, especialmente en los asignadores que utilizan listas de objetos libres .
    • Variables no inicializadas : se utiliza una variable a la que no se le ha asignado un valor. Puede contener información confidencial o bits que no son válidos para el tipo.
      • Los punteros salvajes surgen cuando se utiliza un puntero antes de la inicialización a un estado conocido. Muestran el mismo comportamiento errático que los punteros colgantes, aunque es menos probable que pasen desapercibidos.
      • Libre no válido : pasar una dirección no válida a libre puede dañar el montón .
    • Liberación no coincidente : cuando se utilizan varios asignadores, se intenta liberar memoria con una función de desasignación de un asignador diferente [26]

Contribuyendo errores

Dependiendo del idioma y el entorno, otros tipos de errores pueden contribuir a la inseguridad de la memoria:

Algunas listas también pueden incluir condiciones de carrera (lecturas/escrituras simultáneas en la memoria compartida) como parte de la seguridad de la memoria (por ejemplo, para el control de acceso). El lenguaje de programación Rust evita muchos tipos de condiciones de carrera basadas en la memoria de forma predeterminada, porque garantiza que haya como máximo un escritor o uno o más lectores. Muchos otros lenguajes de programación, como Java, no evitan automáticamente las condiciones de carrera basadas en la memoria, pero aún así se consideran generalmente lenguajes "seguros para la memoria". Por lo tanto, contrarrestar las condiciones de carrera generalmente no se considera necesario para que un lenguaje se considere seguro para la memoria.

Referencias

  1. ^ abcd Dhurjati, Dinakar; Kowshik, Sumant; Adve, Vikram; Lattner, Chris (1 de enero de 2003). "Seguridad de la memoria sin comprobaciones en 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, Andrew. "Cómo C dificulta la comprobación de los límites de las matrices". Dr. Dobb's . 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 . Electronic Systems Center . ESD-TR-73-51. {{cite journal}}: Requiere citar revista |journal=( ayuda )
  5. ^ ab van der Veen, Victor; 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 clase en informática. Vol. 7462. págs. 86–106. doi :10.1007/978-3-642-33338-5_5. ISBN 978-3-642-33337-8. Recuperado el 13 de marzo de 2017 .
  6. ^ Wojtczuk, Rafal. "Cómo derrotar el parche de pila no ejecutable de Solar Designer". insecure.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 . Mitre. 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). "Una falla grave que estuvo presente en sudo durante 9 años transfiere privilegios de root". Ars Technica .
  10. ^ "Pez en un 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". The Rustonomicon . Rust.org . Consultado el 13 de marzo de 2017 .
  13. ^ Bessey, Al; Engler, Dawson; Block, Ken; Chelf, Ben; Chou, Andy; Fulton, Bryan; Hallem, Seth; Henri-Gros, Charles; Kamsky, Asya; McPeak, Scott (1 de febrero de 2010). "Unos cuantos 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 memoria probabilística para lenguajes no seguros" (PDF) . Actas de la 27.ª Conferencia SIGPLAN de la ACM 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, Gene; Berger, Emery D. (1 de enero de 2010). "DieHarder: Securing the heap" (PDF) . Actas de la 17.ª conferencia de la 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, John. "Uso de la herramienta Memcheck de Valgrind para encontrar errores y fugas de memoria". computing.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 y grupos personalizados son difíciles". Proper Fixation . 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. ^ "Semantic Designs: CheckPointer comparado con otras herramientas de comprobación de seguridad". www.semanticdesigns.com . Semantic Designs, Inc.
  22. ^ "Números de rendimiento de AddressSanitizer". GitHub .
  23. ^ Dhumbumroong, Smith (2020). "BoundWarden: seguridad de memoria espacial reforzada 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 de la comunidad . MITRE . Consultado el 13 de marzo de 2017 .
  26. ^ "CWE-762: Rutinas de administración de memoria no coincidentes". Enumeración de debilidades de la comunidad . MITRE . Consultado el 13 de marzo de 2017 .
  27. ^ "Destructores - la referencia de Rust".
  28. ^ "Fugas - el Rustonomicon".
  29. ^ "Fallas de seguridad causadas por optimizaciones del compilador". www.redhat.com . Consultado el 26 de junio de 2024 .
  30. ^ "NVD - CVE-2009-1897". nvd.nist.gov . Consultado el 26 de junio de 2024 .
Obtenido de "https://es.wikipedia.org/w/index.php?title=Seguridad_de_la_memoria&oldid=1251148450"