AddressSanitizer

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

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

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

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

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

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

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

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

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

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

Когда ошибка обнаружена, Асан печатает подробный отчет как на стандартный вывод и 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. Для этого вам нужно создать исполняемый файл с асан, который в данном случае является /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 и перезагрузка.

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

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

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