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

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 не может проникать в код 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, загрузка fastboot flash и перезагрузка.

Используйте свойство переноса

Подход, описанный в предыдущем разделе, включает 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 не являются ASan'd для SANITIZE_TARGET=address

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

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

Сопроводительная документация