stringtranslate.com

Безопасность памяти

Безопасность памяти — это состояние защищенности от различных программных ошибок и уязвимостей безопасности при работе с доступом к памяти , таких как переполнение буфера и зависшие указатели . [1] Например, Java считается безопасной для памяти, поскольку ее функция обнаружения ошибок во время выполнения проверяет границы массива и разыменовывает указатели. [1] Напротив, C и C++ допускают произвольную арифметику указателей с указателями, реализованными как прямые адреса памяти без возможности проверки границ , [2] и, таким образом, являются потенциально небезопасными для памяти . [3]

История

Ошибки памяти впервые были рассмотрены в контексте управления ресурсами (вычислениями) и систем разделения времени , в попытке избежать таких проблем, как fork bombs . [4] Разработки были в основном теоретическими до червя Морриса , который использовал переполнение буфера в fingerd . [5] После этого область компьютерной безопасности быстро развивалась, обостряясь множеством новых атак, таких как атака return-to-libc , и защитных методов, таких как неисполняемый стек [6] и рандомизация макета адресного пространства . Рандомизация предотвращает большинство атак переполнения буфера и требует от злоумышленника использовать heap spraying или другие зависящие от приложения методы для получения адресов, хотя ее принятие было медленным. [5] Однако развертывание технологии, как правило, ограничивается рандомизацией библиотек и расположением стека.

Влияние

В 2019 году инженер по безопасности Microsoft сообщил, что 70% всех уязвимостей безопасности были вызваны проблемами безопасности памяти. [7] В 2020 году команда Google также сообщила, что 70% всех «серьезных ошибок безопасности» в Chromium были вызваны проблемами безопасности памяти. Многие другие громкие уязвимости и эксплойты в критически важном программном обеспечении в конечном итоге возникли из-за отсутствия безопасности памяти, включая Heartbleed [8] и давнюю ошибку повышения привилегий в sudo . [9] Распространенность и серьезность уязвимостей и эксплойтов, возникающих из-за проблем безопасности памяти, побудили нескольких исследователей безопасности описать выявление проблем безопасности памяти как «стрельбу по рыбе в бочке». [10]

Подходы

Некоторые современные языки программирования высокого уровня по умолчанию безопасны для памяти [ требуется ссылка ] , хотя и не полностью, поскольку они проверяют только свой собственный код, а не систему, с которой взаимодействуют. Автоматическое управление памятью в форме сборки мусора является наиболее распространенной техникой для предотвращения некоторых проблем безопасности памяти, поскольку оно предотвращает распространенные ошибки безопасности памяти, такие как использование после освобождения для всех данных, выделенных в среде выполнения языка. [11] В сочетании с автоматической проверкой границ при всех обращениях к массиву и отсутствием поддержки арифметики необработанных указателей языки со сборкой мусора обеспечивают надежные гарантии безопасности памяти (хотя гарантии могут быть слабее для низкоуровневых операций, явно помеченных как небезопасные, таких как использование интерфейса внешней функции ). Однако издержки производительности сборки мусора делают эти языки непригодными для определенных приложений, критичных к производительности. [1]

Для языков, использующих ручное управление памятью , безопасность памяти обычно не гарантируется средой выполнения. Вместо этого свойства безопасности памяти должны либо гарантироваться компилятором с помощью статического анализа программы и автоматизированного доказательства теорем , либо тщательно управляться программистом во время выполнения. [11] Например, язык программирования Rust реализует проверку заимствований для обеспечения безопасности памяти, [12] в то время как C и C++ не предоставляют никаких гарантий безопасности памяти. Значительное количество программного обеспечения, написанного на C и C++, побудило разработать внешние инструменты статического анализа, такие как Coverity , который предлагает статический анализ памяти для C. [13]

DieHard, [14] его переработанный DieHarder, [15] и Allinea Distributed Debugging Tool — это специальные распределители кучи, которые выделяют объекты на своей собственной случайной странице виртуальной памяти, позволяя останавливать и отлаживать недействительные чтения и записи в точной инструкции, которая их вызывает. Защита основана на аппаратной защите памяти, и поэтому накладные расходы обычно незначительны, хотя они могут значительно возрасти, если программа интенсивно использует выделение. [16] Рандомизация обеспечивает только вероятностную защиту от ошибок памяти, но часто может быть легко реализована в существующем программном обеспечении путем повторной компоновки двоичного файла.

Инструмент проверки памяти Valgrind использует симулятор набора инструкций и запускает скомпилированную программу в виртуальной машине проверки памяти, обеспечивая гарантированное обнаружение подмножества ошибок памяти во время выполнения. Однако он обычно замедляет программу в 40 раз [17] и, кроме того, должен быть явно проинформирован о пользовательских распределителях памяти. [18] [19]

Имея доступ к исходному коду, существуют библиотеки, которые собирают и отслеживают допустимые значения для указателей («метаданные») и проверяют каждый доступ указателя на соответствие метаданным на предмет действительности, например, сборщик мусора Boehm . [20] В общем, безопасность памяти можно безопасно обеспечить, используя отслеживание сборки мусора и вставку проверок времени выполнения при каждом доступе к памяти; этот подход имеет накладные расходы, но меньше, чем у Valgrind. Все языки со сборкой мусора используют этот подход. [1] Для C и C++ существует множество инструментов, которые выполняют преобразование кода во время компиляции для выполнения проверок безопасности памяти во время выполнения, например, CheckPointer [21] и AddressSanitizer , который в среднем устанавливает коэффициент замедления 2. [22]

BoundWarden — это новый подход к обеспечению пространственной памяти, который использует комбинацию преобразований во время компиляции и методов параллельного мониторинга во время выполнения. [23]

Тестирование методом фаззинга хорошо подходит для поиска ошибок безопасности памяти и часто используется в сочетании с динамическими средствами проверки, такими как AddressSanitizer.

Классификация ошибок безопасности памяти

Могут возникнуть различные типы ошибок памяти: [24] [25]

Внесение ошибок

В зависимости от языка и среды другие типы ошибок могут способствовать небезопасности памяти:

Некоторые списки могут также включать состояния гонки (одновременные чтения/записи в общую память) как часть безопасности памяти (например, для контроля доступа). Язык программирования Rust по умолчанию предотвращает многие виды состояний гонки, основанных на памяти, поскольку он гарантирует, что есть не более одного писателя или одного или нескольких читателей. Многие другие языки программирования, такие как Java, автоматически не предотвращают состояния гонки, основанные на памяти, но все еще считаются языками «безопасности памяти». Поэтому противодействие состояниям гонки, как правило, не считается необходимым для того, чтобы язык считался безопасным для памяти.

Ссылки

  1. ^ abcd Dhurjati, Dinakar; Kowshik, Sumant; Adve, Vikram; Lattner, Chris (1 января 2003 г.). "Безопасность памяти без проверок во время выполнения или сборки мусора" (PDF) . Труды конференции ACM SIGPLAN 2003 г. по языку, компилятору и инструменту для встраиваемых систем . ACM. стр. 69–80. doi :10.1145/780732.780743. ISBN 1581136471. S2CID  1459540 . Получено 13 марта 2017 г. .
  2. ^ Кёниг, Эндрю. «Как язык программирования C затрудняет проверку границ массива». Dr. Dobb's . Получено 13 марта 2017 г.
  3. ^ Акритидис, Периклис (июнь 2011 г.). "Практическая безопасность памяти для C" (PDF) . Технический отчет - Кембриджский университет. Компьютерная лаборатория . Кембриджский университет, Компьютерная лаборатория. ISSN  1476-2986. UCAM-CL-TR-798 . Получено 13 марта 2017 г. .
  4. ^ Андерсон, Джеймс П. «Исследование планирования компьютерной безопасности» (PDF) . 2. Центр электронных систем . ESD-TR-73-51. {{cite journal}}: Цитировать журнал требует |journal=( помощь )
  5. ^ ab van der Veen, Victor; dutt-Sharma, Nitish; Cavallaro, Lorenzo; Bos, Herbert (2012). «Ошибки памяти: прошлое, настоящее и будущее» (PDF) . Исследования атак, вторжений и защиты . Конспект лекций по информатике. Том 7462. С. 86–106. doi :10.1007/978-3-642-33338-5_5. ISBN 978-3-642-33337-8. Получено 13 марта 2017 г. .
  6. ^ Войтчук, Рафал. «Побеждая неисполняемый патч стека Solar Designer». insecure.org . Получено 13 марта 2017 г.
  7. ^ "Microsoft: 70 процентов всех ошибок безопасности — это проблемы с безопасностью памяти". ZDNET . Получено 21 сентября 2022 г. .
  8. ^ "CVE-2014-0160". Распространенные уязвимости и риски . Mitre. Архивировано из оригинала 24 января 2018 г. Получено 8 февраля 2018 г.
  9. ^ Гудин, Дэн (4 февраля 2020 г.). «Серьезная уязвимость, которая скрывалась в sudo в течение 9 лет, приводит к передаче прав root». Ars Technica .
  10. ^ "Рыба в бочке". fishinabarrel.github.io . Получено 21 сентября 2022 г. .
  11. ^ ab Crichton, Will. "CS 242: Безопасность памяти". stanford-cs242.github.io . Получено 22 сентября 2022 г. .
  12. ^ "Ссылки". The Rustonomicon . Rust.org . Получено 13 марта 2017 г. .
  13. ^ Бесси, Эл; Энглер, Доусон; Блок, Кен; Челф, Бен; Чоу, Энди; Фултон, Брайан; Халлем, Сет; Анри-Гро, Чарльз; Камски, Ася; Макпик, Скотт (1 февраля 2010 г.). «Несколько миллиардов строк кода позже». Сообщения ACM . 53 (2): 66–75. doi :10.1145/1646353.1646374. S2CID  2611544.
  14. ^ Бергер, Эмери Д.; Зорн, Бенджамин Г. (1 января 2006 г.). "DieHard: Вероятностная безопасность памяти для небезопасных языков" (PDF) . Труды 27-й конференции ACM SIGPLAN по проектированию и реализации языков программирования . ACM. стр. 158–168. doi :10.1145/1133981.1134000. ISBN 1595933204. S2CID  8984358 . Получено 14 марта 2017 г. .
  15. ^ Новарк, Джин; Бергер, Эмери Д. (1 января 2010 г.). "DieHarder: Securing the heap" (PDF) . Труды 17-й конференции ACM по компьютерной и коммуникационной безопасности . ACM. стр. 573–584. doi :10.1145/1866307.1866371. ISBN 9781450302456. S2CID  7880497 . Получено 14 марта 2017 г. .
  16. ^ "Отладка памяти в Allinea DDT". Архивировано из оригинала 2015-02-03.
  17. ^ Джилленхол, Джон. «Использование инструмента Memcheck от Valgrind для поиска ошибок и утечек памяти». computing.llnl.gov . Архивировано из оригинала 7 ноября 2018 г. . Получено 13 марта 2017 г. .
  18. ^ "Memcheck: детектор ошибок памяти". Руководство пользователя Valgrind . valgrind.org . Получено 13 марта 2017 г. .
  19. ^ Крейнин, Йосси. "Почему пользовательские распределители/пулы сложны". Правильная фиксация . Получено 13 марта 2017 г.
  20. ^ «Использование мусоросборника в качестве детектора утечек». www.hboehm.info . Получено 14 марта 2017 г. .
  21. ^ "Semantic Designs: CheckPointer в сравнении с другими инструментами проверки безопасности". www.semanticdesigns.com . Semantic Designs, Inc.
  22. ^ "AddressSanitizerPerformanceNumbers". GitHub .
  23. ^ Dhumbumroong, Smith (2020). «BoundWarden: Безопасность пространственной памяти, усиленная потоками посредством преобразований во время компиляции». Science of Computer Programming . 198 : 102519. doi : 10.1016/j.scico.2020.102519. S2CID  224925197.
  24. ^ Gv, Naveen. «Как избегать, находить (и исправлять) ошибки памяти в коде C/C++». Cprogramming.com . Получено 13 марта 2017 г. .
  25. ^ "CWE-633: Слабости, влияющие на память". Перечень слабостей сообщества . MITRE . Получено 13 марта 2017 г.
  26. ^ "CWE-762: Несоответствующие процедуры управления памятью". Community Weakness Enumeration . MITRE . Получено 13 марта 2017 г. .
  27. ^ «Деструкторы — справочник по Rust».
  28. ^ «Утечка — Рустономикон».
  29. ^ «Уязвимости безопасности, вызванные оптимизацией компилятора». www.redhat.com . Получено 2024-06-26 .
  30. ^ "NVD - CVE-2009-1897". nvd.nist.gov . Получено 2024-06-26 .