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

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

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

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

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

Android 10 и основная ветвь AOSP на AArch64 поддерживают ASan с аппаратным ускорением (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 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, загрузка с флэш-памяти fastboot и перезагрузка.

Использование свойства обертки

Подход, описанный в предыдущем разделе, помещает 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 .

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

SANITIZE_TARGET

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-инструментированные в /data/asan/lib (второй вызов make). Исполняемые файлы из второй сборки перезаписывают файлы из первой сборки. Исполняемые файлы, оснащенные ASan, получают другой путь поиска библиотеки, который включает /data/asan/lib перед /system/lib за счет использования /system/bin/linker_asan в PT_INTERP .

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

Некоторые цели нельзя построить с помощью ASan:

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

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

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

Сопутствующая документация