AddressSanitizer (или ASan ) - это инструмент программирования с открытым исходным кодом, который обнаруживает ошибки повреждения памяти, такие как переполнение буфера или доступ к висящему указателю (использование после освобождения). AddressSanitizer основан на инструментарии компилятора и теневой памяти с прямым отображением . AddressSanitizer в настоящее время реализован в Clang (начиная с версии 3.1 [1] ), GCC (начиная с версии 4.8 [2] ), Xcode (начиная с версии 7.0 [3] ) и MSVC. (широко доступен, начиная с версии 16.9 [4] ). В среднем инструментарий увеличивает время обработки примерно на 73% и использование памяти на 240%. [5]
Пользователи
Разработчики Chromium и Firefox являются активными пользователями AddressSanitizer; [6] [7] инструмент обнаружил сотни ошибок в этих веб-браузерах. [8] В FFmpeg [9] и FreeType был обнаружен ряд ошибок . [10] ядро Linux позволило AddressSanitizer для x86-64 архитектуры , как в Linux версии 4.0.
KernelAddressSanitizer
KernelAddressSanitizer ( Касан ) обнаруживает динамические ошибки памяти в ядре Linux. [11] Инструментарий ядра требует специальной функции в компиляторе, предоставляющей параметр -fsanitize=kernel-addressкомандной строки, поскольку ядра не используют то же адресное пространство, что и обычные программы. [12] [13]
Примеры
Использование кучи после освобождения
// Для компиляции: g ++ -O -g -fsanitize = адрес heap-use-after-free.ccint main ( int argc , char ** argv ) { int * array = new int [ 100 ]; массив delete [] ; вернуть массив [ argc ]; // БУМ}
$ ./a.out== 5587 == ОШИБКА: AddressSanitizer: использование кучи после освобождения по адресу 0x61400000fe44 на ПК 0x47b55f bp 0x7ffc36b28200 sp 0x7ffc36b281f8ЧИТАТЬ размер 4 на 0x61400000fe44 резьба T0 # 0 0x47b55e в главном /home/test/example_UseAfterFree.cc:5 # 1 0x7f15cfe71b14 в __libc_start_main (/lib64/libc.so.6+0x21b14) # 2 0x47b44c в _start (/root/a.out+0x47b44c)0x61400000fe44 находится в 4 байтах внутри 400-байтовой области [0x61400000fe40,0x61400000ffd0)освобожден потоком T0 здесь: # 0 0x465da9 в операторе delete [] (void *) (/root/a.out+0x465da9) # 1 0x47b529 в основном /home/test/example_UseAfterFree.cc:4ранее выделенный потоком T0 здесь: # 0 0x465aa9 в операторе new [] (длинное без знака) (/root/a.out+0x465aa9) # 1 0x47b51e в основном /home/test/example_UseAfterFree.cc:3РЕЗЮМЕ: AddressSanitizer: heap-use-after-free /home/test/example_UseAfterFree.cc:5 mainТень байтов вокруг ошибочного адреса: 0x0c287fff9f70: фа фа фа фа фа фа фа фа фа фа фа фа 0x0c287fff9f80: фа фа фа фа фа фа фа фа фа фа фа фа 0x0c287fff9f90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c287fff9fa0: фа фа фа фа фа фа фа фа фа фа фа фа 0x0c287fff9fb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa=> 0x0c287fff9fc0: fa fa fa fa fa fa fa fa [fd] fd fd fd fd fd fd fd 0x0c287fff9fd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c287fff9fe0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c287fff9ff0: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa 0x0c287fffa000: фа фа фа фа фа фа фа фа фа фа фа фа 0x0c287fffa010: фа фа фа фа фа фа фа фа фа фа фа фаЛегенда байта тени (один байт тени соответствует 8 байтам приложения): Адресный: 00 Частично адресуемый: 01 02 03 04 05 06 07 Куча слева redzone: fa Куча правой красной зоны: fb Освободившаяся область кучи: fd Стек левая красная зона: f1 Стек средняя красная зона: f2 Стек правая красная зона: f3 Стек частичная красная зона: f4 Стек после возврата: f5 Использование стека после прицела: f8 Глобальная красная зона: f9 Глобальный порядок инициализации: f6 Отравлен пользователем: f7 ASan внутренний: fe== 5587 == ПРЕРЫВАНИЕ
Переполнение буфера кучи
// ЗАПУСК: clang ++ -O -g -fsanitize = адрес% t && ./a.outint main ( int argc , char ** argv ) { int * array = new int [ 100 ]; массив [ 0 ] = 0 ; int res = массив [ argc + 100 ]; // БУМ массив delete [] ; return res ;}
== 25372 == ОШИБКА: AddressSanitizer: переполнение буфера кучи по адресу 0x61400000ffd4 на ПК 0x0000004ddb59 bp 0x7fffea6005a0 sp 0x7fffea600598ЧИТАТЬ размер 4 на 0x61400000ffd4 резьба T0 # 0 0x46bfee в главном /tmp/main.cpp:4:130x61400000ffd4 расположен на 4 байта справа от 400-байтовой области [0x61400000fe40,0x61400000ffd0)выделено потоком T0 здесь: # 0 0x4536e1 в операторе delete [] (void *) # 1 0x46bfb9 в главном /tmp/main.cpp:2:16
Стек-буфер-переполнение
// ЗАПУСК: clang -O -g -fsanitize = адрес% t && ./a.outint main ( int argc , char ** argv ) { int stack_array [ 100 ]; stack_array [ 1 ] = 0 ; вернуть stack_array [ argc + 100 ]; // БУМ}
== 7405 == ОШИБКА: AddressSanitizer: переполнение буфера стека по адресу 0x7fff64740634 на ПК 0x46c103 bp 0x7fff64740470 sp 0x7fff64740468ЧИТАТЬ размер 4 на 0x7fff64740634 резьба T0 # 0 0x46c102 в основном файле /tmp/example_StackOutOfBounds.cc:5Адрес 0x7fff64740634 находится в стеке потока T0 по смещению 436 в кадре. # 0 0x46bfaf в основном файле /tmp/example_StackOutOfBounds.cc:2 В этом кадре 1 объект (ы): [32, 432) 'stack_array' <== Доступ к памяти по смещению 436 вызывает переполнение этой переменной
Глобальное переполнение буфера
// ЗАПУСК: clang -O -g -fsanitize = адрес% t && ./a.out int global_array [ 100 ] = { -1 }; int main ( int argc , char ** argv ) { return global_array [ argc + 100 ]; // БУМ }
== 7455 == ОШИБКА: AddressSanitizer: глобальное переполнение буфера по адресу 0x000000689b54 на ПК 0x46bfd8 bp 0x7fff515e5ba0 sp 0x7fff515e5b98ЧИТАТЬ размер 4 на 0x000000689b54 резьба T0 # 0 0x46bfd7 в основном файле /tmp/example_GlobalOutOfBounds.cc:40x000000689b54 расположен на 4 байта справа от глобальная переменная global_array из example_GlobalOutOfBounds.cc (0x6899c0) размером 400
Ограничения
AddressSanitizer не обнаруживает никаких неинициализированных операций чтения из памяти (но это обнаруживает MemorySanitizer [14] ), а только обнаруживает некоторые ошибки использования после возврата. [15] Он также не способен обнаруживать все ошибки произвольного повреждения памяти или все ошибки произвольной записи из-за целочисленного недополнения / переполнения (когда целое число с неопределенным поведением используется для вычисления смещения адресов памяти). Смежные буферы в структурах и классах не защищены от переполнения, отчасти для предотвращения нарушения обратной совместимости. [16]
Смотрите также
- Intel MPX
- Средство проверки приложений (AppVerif.exe) в Microsoft Windows SDK
Рекомендации
- ^ "Примечания к выпуску LLVM 3.1" . LLVM . Проверено 8 февраля 2014 .
- ^ «Примечания к выпуску GCC 4.8» . GCC . Проверено 8 февраля 2014 .
- ^ «Address Sanitizer | Документация для разработчиков Apple» .
- ^ «Заметки о выпуске Visual Studio 2019 версии 16.9» . Microsoft . Проверено 5 марта 2021 года .
- ^ Константин Серебряный; Дерек Брюнинг; Александр Потапенко; Дмитрий Вьюков. «AddressSanitizer: средство быстрой проверки корректности адресов» (PDF) . Материалы конференции USENIX 2012 по Ежегодной технической конференции .
- ^ Абхишек Арья; Крис Неккар; Команда безопасности Chrome. «Фаззинг для безопасности» .
- ^ «Защита Firefox: пробуем новые методы анализа кода» . Архивировано из оригинала на 2016-03-07 . Проверено 18 июня 2018 .
- ^ «Некоторые из ошибок, обнаруженных AddressSanitizer» .
- ^ Матеуш Юрчик; Гинваэль Холодный Ветер (10 января 2014 г.). «FFmpeg и тысяча исправлений» .
- ^ «Результаты поиска AddressSanitizer в FreeType Bugs» .
- ^ "KernelAddressSanitizer (КАСАН)" . Архивировано из оригинала на 2015-09-15.
- ^ Джейк Эдж. «Средство очистки адресов ядра» .
- ^ Джонатан Корбет. «3.20 окно слияния, часть 2» .
- ^ «MemorySanitizer» .
- ^ "ComparisonOfMemoryTools" . AddressSanitizer Wiki . Проверено 1 декабря 2017 года .
- ^ «Обход AddressSanitizer» (PDF) . Эрик Уимберли . Проверено 1 июля 2014 года .
Внешние ссылки
- Группа Google AddressSanitizer (без списка рассылки)
- Страница проекта AddressSanitizer
- Документация AddressSanitizer (Clang)