АдресДезинфицирующее средство

AddressSanitizer (ASan) — это быстрый инструмент на основе компилятора для обнаружения ошибок памяти в машинном коде.

ASan обнаруживает:

  • Переполнение/незаполнение буфера стека и кучи
  • Использование кучи после освобождения
  • Использование стека вне области действия
  • Двойной бесплатный/дикий бесплатный

ASan работает как на 32-битном, так и на 64-битном ARM, а также на x86 и x86-64. Накладные расходы на ЦП ASan составляют примерно 2x, накладные расходы на размер кода — от 50% до 2x, а также большие накладные расходы на память (в зависимости от ваших шаблонов распределения, но порядка 2x).

Android 10 и последняя ветка релиза AOSP на AArch64 поддерживают Hardware-assisted AddressSanitizer (HWASan) , похожий инструмент с меньшими затратами оперативной памяти и большим диапазоном обнаруживаемых ошибок. HWASan обнаруживает использование стека после возврата, в дополнение к ошибкам, обнаруженным ASan.

HWASan имеет схожие накладные расходы на ЦП и размер кода, но гораздо меньшие накладные расходы на ОЗУ (15%). HWASan недетерминирован. Существует всего 256 возможных значений тегов, поэтому существует фиксированная вероятность пропуска любой ошибки 0,4%. HWASan не имеет красных зон ограниченного размера ASan для обнаружения переполнения и карантина ограниченной емкости для обнаружения использования после освобождения, поэтому для HWASan не имеет значения, насколько велико переполнение или как давно была освобождена память. Это делает HWASan лучше, чем ASan. Вы можете прочитать больше о дизайне HWASan или об использовании HWASan на Android .

ASan обнаруживает переполнения стека/глобальное переполнение в дополнение к переполнению кучи и работает быстро с минимальными затратами памяти.

В этом документе описывается, как собрать и запустить части/весь Android с помощью ASan. Если вы создаете приложение SDK/NDK с помощью ASan, вместо этого см. Address Sanitizer .

Очистите отдельные исполняемые файлы с помощью ASan

Добавьте LOCAL_SANITIZE:=address или sanitize: { address: true } в правило сборки для исполняемого файла. Вы можете выполнить поиск в коде для существующих примеров или найти другие доступные санитайзеры.

При обнаружении ошибки ASan выводит подробный отчет как на стандартный вывод, так и в logcat , а затем завершает процесс.

Очистите общие библиотеки с помощью ASan

Из-за особенностей работы ASan библиотека, созданная с помощью ASan, может использоваться только исполняемым файлом, созданным с помощью ASan.

Чтобы очистить общую библиотеку, которая используется в нескольких исполняемых файлах, не все из которых построены с помощью ASan, вам нужны две копии библиотеки. Рекомендуемый способ сделать это — добавить следующее в Android.mk для соответствующего модуля:

LOCAL_SANITIZE:=address
LOCAL_MODULE_RELATIVE_PATH := asan

Это помещает библиотеку в /system/lib/asan вместо /system/lib . Затем запустите исполняемый файл с помощью:

LD_LIBRARY_PATH=/system/lib/asan

Для системных демонов добавьте следующее в соответствующий раздел /init.rc или /init.$device$.rc .

setenv LD_LIBRARY_PATH /system/lib/asan

Проверьте, что процесс использует библиотеки из /system/lib/asan если они есть, прочитав /proc/$PID/maps . Если это не так, вам может потребоваться отключить SELinux:

adb root
adb shell setenforce 0
# restart the process with adb shell kill $PID
# if it is a system service, or may be adb shell stop; adb shell start.

Улучшенные трассировки стека

ASan использует быстрый, основанный на указателях кадров раскручиватель для записи трассировки стека для каждого события выделения и освобождения памяти в программе. Большая часть Android построена без указателей кадров. В результате вы часто получаете только один или два значимых кадра. Чтобы исправить это, либо пересоберите библиотеку с помощью ASan (рекомендуется!), либо с помощью:

LOCAL_CFLAGS:=-fno-omit-frame-pointer
LOCAL_ARM_MODE:=arm

Или установите ASAN_OPTIONS=fast_unwind_on_malloc=0 в среде процесса. Последнее может быть очень интенсивным для процессора, в зависимости от нагрузки.

Символизация

Изначально отчеты ASan содержат ссылки на смещения в двоичных файлах и разделяемых библиотеках. Существует два способа получить информацию об исходном файле и строке:

  • Убедитесь, что двоичный файл llvm-symbolizer присутствует в /system/bin . llvm-symbolizer собирается из исходных кодов в third_party/llvm/tools/llvm-symbolizer .
  • Отфильтруйте отчет с помощью скрипта external/compiler-rt/lib/asan/scripts/symbolize.py .

Второй подход может предоставить больше данных (то есть местоположений file:line ) из-за доступности символьных библиотек на хосте.

ASan в приложениях

ASan не может заглянуть в код Java, но может обнаружить ошибки в библиотеках JNI. Для этого вам нужно собрать исполняемый файл с помощью ASan, который в данном случае является /system/bin/app_process( 32|64 ) . Это включает ASan во всех приложениях на устройстве одновременно, что является большой нагрузкой, но устройство с 2 ГБ оперативной памяти должно с этим справиться.

Добавьте LOCAL_SANITIZE:=address в правило сборки app_process в frameworks/base/cmds/app_process . Пока игнорируйте цель app_process__asan в том же файле (если она все еще там, когда вы это читаете).

Отредактируйте раздел service zygote соответствующего файла system/core/rootdir/init.zygote( 32|64 ).rc , чтобы добавить следующие строки в блок строк с отступом, содержащий class main , также с отступом на ту же величину:

    setenv LD_LIBRARY_PATH /system/lib/asan:/system/lib
    setenv ASAN_OPTIONS allow_user_segv_handler=true

Сборка, синхронизация adb, быстрая загрузка flash и перезагрузка.

Используйте свойство wrap

Подход, описанный в предыдущем разделе, помещает ASan в каждое приложение в системе (фактически, в каждого потомка процесса Zygote). С ASan можно запустить только одно (или несколько) приложений, пожертвовав некоторой нагрузкой на память ради более медленного запуска приложения.

Это можно сделать, запустив приложение со свойством wrap. Следующий пример запускает приложение Gmail под управлением ASan:

adb root
adb shell setenforce 0  # disable SELinux
adb shell setprop wrap.com.google.android.gm "asanwrapper"

В этом контексте asanwrapper переписывает /system/bin/app_process в /system/bin/asan/app_process , который создан с помощью ASan. Он также добавляет /system/lib/asan в начало пути поиска динамической библиотеки. Таким образом, библиотеки с инструментами ASan из /system/lib/asan имеют приоритет перед обычными библиотеками в /system/lib при запуске с asanwrapper .

При обнаружении ошибки приложение аварийно завершает работу, а отчет записывается в журнал.

САНИТИЗАЦИЯ_ЦЕЛИ

Android 7.0 и выше поддерживает сборку всей платформы Android с помощью ASan одновременно. (Если вы собираете версию выше Android 9, лучшим выбором будет HWASan.)

Выполните следующие команды в том же дереве сборки.

make -j42
SANITIZE_TARGET=address make -j42

В этом режиме userdata.img содержит дополнительные библиотеки и также должен быть прошит на устройство. Используйте следующую командную строку:

fastboot flash userdata && fastboot flashall

Это создает два набора общих библиотек: обычные в /system/lib (первый вызов make) и ASan-instrumented в /data/asan/lib (второй вызов make). Исполняемые файлы из второй сборки перезаписывают исполняемые файлы из первой сборки. Исполняемые файлы ASan-instrumented получают другой путь поиска библиотек, который включает /data/asan/lib перед /system/lib посредством использования /system/bin/linker_asan в PT_INTERP .

Система сборки затирает промежуточные каталоги объектов, когда значение $SANITIZE_TARGET изменилось. Это заставляет пересобрать все цели, сохраняя установленные двоичные файлы в /system/lib .

Некоторые цели не могут быть построены с помощью ASan:

  • Статически связанные исполняемые файлы
  • LOCAL_CLANG:=false цели
  • LOCAL_SANITIZE:=false не обработаны ASan для SANITIZE_TARGET=address

Подобные исполняемые файлы пропускаются в сборке SANITIZE_TARGET , а версия из первого вызова make остается в /system/bin .

Такие библиотеки создаются без ASan. Они могут содержать некоторый код ASan из статических библиотек, от которых они зависят.

Подтверждающая документация