La seguridad de la memoria es el estado de estar protegido de varios errores de software y vulnerabilidades de seguridad cuando se trata de 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 comprueba los límites de la matriz y las desreferencias de los punteros. [1] En contraste, 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 y los sistemas de tiempo compartido , en un esfuerzo por evitar problemas como bombas de horquilla . [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, 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 fumigación de pila 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 se limitan típicamente a las bibliotecas aleatorias y la ubicación de la pila.
Enfoques
DieHard, [7] su rediseño DieHarder, [8] y la herramienta de depuración distribuida de 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 provoca . La protección se basa en la protección de la memoria del hardware y, por lo tanto, la sobrecarga generalmente no es sustancial, aunque puede aumentar significativamente si el programa hace un uso intensivo de la asignación. [9] 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, [10] y, además, debe ser informado explícitamente de los asignadores de memoria personalizados. [11] [12]
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 verificar su validez, como el recolector de basura Boehm . [13] En general, la seguridad de la memoria puede garantizarse de forma segura mediante el seguimiento 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 gastos generales, pero menos que los 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 [14] y AddressSanitizer que impone un factor de desaceleración promedio de 2. [15]
Otro enfoque utiliza el análisis de programa estático y la demostración automatizada de teoremas para garantizar que el programa esté libre de errores de memoria. Por ejemplo, el lenguaje de programación Rust implementa un comprobador de préstamos para garantizar la seguridad de la memoria. [16] Herramientas como Coverity ofrecen análisis de memoria estática para C. [17] Los punteros inteligentes de C ++ son una forma limitada de este enfoque.
Tipos de errores de memoria
Pueden ocurrir muchos tipos diferentes de errores de memoria: [18] [19]
- Errores de acceso : lectura / escritura no válida de un puntero
- Desbordamiento del búfer : las escrituras fuera del límite pueden dañar el contenido de los objetos adyacentes o los datos internos (como la información contable del montón ) o lasdirecciones de retorno .
- Lectura excesiva del búfer: las lecturas fuera del límite pueden revelar datos confidenciales o ayudar a los atacantes a evitar la aleatorización del diseño del espacio de direcciones .
- Condición de carrera : lecturas / escrituras simultáneas en la memoria compartida
- Fallo de página no válida : acceder a un puntero fuera del espacio de memoria virtual. Una desreferencia de puntero nulo a menudo causará una excepción o la terminación del programa en la mayoría de los entornos, pero puede causar daños en los núcleos del sistema operativoo sistemas sin protección de memoria , o cuando el uso del puntero nulo implica un desplazamiento grande o negativo.
- Úselo después de liberar : desreferenciar un puntero colgante que almacena la dirección de un objeto que ha sido eliminado.
- Variables no inicializadas : se utiliza una variable a la que no se le ha asignado un valor. Puede contener un valor no deseado o, en algunos idiomas, corrupto.
- Puntero nulo desreferenciar - eliminación de referencias a un puntero no válido o un puntero a la memoria que no ha sido asignado
- Los punteros salvajes surgen cuando se usa un puntero antes de la inicialización a algún estado conocido. Muestran el mismo comportamiento errático que los punteros colgantes, aunque es menos probable que pasen desapercibidos.
- Pérdida de memoria : cuando no se realiza un seguimiento del uso de la memoria o se realiza un seguimiento incorrecto
- Agotamiento de la pila : se produce cuando un programa se queda sin espacio en la pila, normalmente debido a una recursividad demasiado profunda. Una página de protección normalmente detiene el programa, evitando la corrupción de la memoria, pero las funciones con marcos de pila grandespueden omitir la página.
- Agotamiento de la pila : el programa intenta asignar más memoria que la cantidad disponible. En algunos idiomas, esta condición se debe verificar manualmente después de cada asignación.
- Doble gratis : las llamadas repetidas a liberar pueden liberar prematuramente un nuevo objeto en la misma dirección. Si la dirección exacta no se ha reutilizado, pueden producirse otros daños, especialmente en asignadores que utilizan listas libres .
- Gratis no válido : pasar una dirección no válida a free puede dañar el montón .
- Libre no coincidente : cuando se utilizan varios asignadores, se intenta liberar memoria con una función de desasignación de un asignador diferente [20]
- Alias no deseado : cuando se asigna la misma ubicación de memoria y se modifica dos veces para fines no relacionados.
Referencias
- ^ a b c Dhurjati, Dinakar; Kowshik, Sumant; Adve, Vikram; Lattner, Chris (1 de enero de 2003). "Seguridad de la memoria sin comprobaciones en tiempo de ejecución o recolección de basura" (PDF) . Actas de la Conferencia ACM SIGPLAN de 2003 sobre lenguaje, compilador y herramienta para sistemas integrados . ACM: 69–80. doi : 10.1145 / 780732.780743 . ISBN 1581136471. Consultado el 13 de marzo de 2017 .
- ^ Koenig, Andrew. "Cómo C hace que sea difícil comprobar los límites de la matriz" . Dr. Dobb's . Consultado el 13 de marzo de 2017 .
- ^ Akritidis, Periklis (junio de 2011). "Práctica seguridad 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 .
- ^ Anderson, James P. "Estudio de planificación de seguridad informática" (PDF) . 2 . Centro de Sistemas Electrónicos . ESD-TR-73-51. Cite journal requiere
|journal=
( ayuda ) - ^ a b van der Veen, Victor; dutt-Sharma, Nitish; Cavallaro, Lorenzo; Bos, Herbert (2012). "Errores de memoria: el pasado, el presente y el futuro" (PDF) . Apuntes de conferencias en informática . 7462 (RAID 2012): 86–106. doi : 10.1007 / 978-3-642-33338-5_5 . ISBN 978-3-642-33337-8. Consultado el 13 de marzo de 2017 .
- ^ Wojtczuk, Rafal. "Derrotando el parche de pila no ejecutable de Solar Designer" . insecure.org . Consultado el 13 de marzo de 2017 .
- ^ 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: 158–168. doi : 10.1145 / 1133981.1134000 . Consultado el 14 de marzo de 2017 .
- ^ Novark, Gene; Berger, Emery D. (1 de enero de 2010). "DieHarder: Asegurar el montón" (PDF) . Actas de la 17ª Conferencia de la ACM sobre seguridad informática y de comunicaciones . ACM: 573–584. doi : 10.1145 / 1866307.1866371 . Consultado el 14 de marzo de 2017 .
- ^ "Depuración de memoria en Allinea DDT" . Archivado desde el original el 3 de febrero de 2015.
- ^ 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 .
- ^ "Memcheck: un detector de errores de memoria" . Manual de usuario de Valgrind . valgrind.org . Consultado el 13 de marzo de 2017 .
- ^ Kreinin, Yossi. "Por qué los asignadores / grupos personalizados son difíciles" . Fijación adecuada . Consultado el 13 de marzo de 2017 .
- ^ "Uso del recolector de basura como detector de fugas" . www.hboehm.info . Consultado el 14 de marzo de 2017 .
- ^ "Diseños semánticos: CheckPointer en comparación con otras herramientas de control de seguridad" . www.semanticdesigns.com . Semantic Designs, Inc.
- ^ "AddressSanitizerPerformanceNumbers" .
- ^ "Referencias" . El Rustonomicon . Rust.org . Consultado el 13 de marzo de 2017 .
- ^ 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 pocos miles de millones de líneas de código más tarde" . Comunicaciones de la ACM . 53 (2): 66–75. doi : 10.1145 / 1646353.1646374 . Consultado el 14 de marzo de 2017 .
- ^ 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 .
- ^ "CWE-633: Debilidades que afectan la memoria" . Enumeración de debilidades de la comunidad . MITRE . Consultado el 13 de marzo de 2017 .
- ^ "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 .