Скудо

Scudo — это динамический распределитель памяти в пользовательском режиме или распределитель кучи , разработанный для обеспечения устойчивости к уязвимостям, связанным с кучей (таким как переполнение буфера в куче , использование после освобождения и двойное освобождение ), сохраняя при этом производительность. Он предоставляет стандартные примитивы выделения и освобождения C (такие как malloc и free), а также примитивы C++ (такие как new и delete).

Scudo — это скорее средство смягчения последствий, чем полноценный детектор ошибок памяти, такой как AddressSanitizer (ASan) .

Начиная с выпуска Android 11, scudo используется для всего собственного кода (за исключением устройств с низким объемом памяти, где все еще используется jemalloc). Во время выполнения все собственные выделения и освобождения кучи обслуживаются Scudo для всех исполняемых файлов и их библиотечных зависимостей, и процесс прерывается, если в куче обнаруживается повреждение или подозрительное поведение.

Scudo имеет открытый исходный код и является частью проекта compiler-rt компании LLVM. Документация доступна по адресу https://llvm.org/docs/ScudoHardenedAllocator.html . Среда выполнения Scudo поставляется как часть набора инструментов Android, а в Soong и Make была добавлена ​​поддержка, позволяющая легко включить распределитель в двоичном файле.

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

Кастомизация

Некоторые параметры распределителя можно определить для каждого процесса несколькими способами:

  • Статически: определите в программе функцию __scudo_default_options , которая возвращает строку параметров для анализа. Эта функция должна иметь следующий прототип: extern "C" const char *__scudo_default_options() .
  • Динамически: используйте переменную среды SCUDO_OPTIONS содержащую строку параметров для анализа. Параметры, определенные таким образом, переопределяют любые определения, сделанные с помощью __scudo_default_options .

Доступны следующие варианты.

Вариант 64-битная версия по умолчанию 32-битная версия по умолчанию Описание
QuarantineSizeKb 256 64 Размер (в КБ) карантина, используемый для задержки фактического освобождения фрагментов. Более низкое значение может уменьшить использование памяти, но снизить эффективность смягчения последствий; отрицательное значение возвращает значения по умолчанию. Установка для этого параметра и ThreadLocalQuarantineSizeKb значения 0 полностью отключает карантин.
QuarantineChunksUpToSize 2048 512 Размер (в байтах), до которого фрагменты могут быть помещены в карантин.
ThreadLocalQuarantineSizeKb 64 16 Размер (в КБ) кэша каждого потока, используемого для разгрузки глобального карантина. Более низкое значение может снизить использование памяти, но может увеличить конфликты в глобальном карантине. Установка для этого параметра и QuarantineSizeKb значения 0 полностью отключает карантин.
DeallocationTypeMismatch false false Включает отчеты об ошибках при malloc/delete, new/free, new/delete[]
DeleteSizeMismatch true true Включает отчеты об ошибках при несоответствии размеров новых и удаленных файлов.
ZeroContents false false Включает нулевое содержимое чанка при выделении и освобождении.
allocator_may_return_null false false Указывает, что распределитель может возвращать значение null при возникновении устранимой ошибки вместо завершения процесса.
hard_rss_limit_mb 0 0 Когда RSS процесса достигает этого предела, процесс завершается.
soft_rss_limit_mb 0 0 Когда RSS процесса достигает этого предела, дальнейшие выделения терпят неудачу или возвращают null (в зависимости от значения allocator_may_return_null ), пока RSS не отключится, чтобы разрешить новые выделения.
allocator_release_to_os_interval_ms Н/Д 5000 Влияет только на 64-битный распределитель. Если установлено, пытается освободить неиспользуемую память ОС, но не чаще этого интервала (в миллисекундах). Если значение отрицательное, память не выделяется для ОС.
abort_on_error true true Если установлено, инструмент вызывает abort() вместо _exit() после печати сообщения об ошибке.

Валидация

В настоящее время не существует тестов CTS специально для Scudo. Вместо этого убедитесь, что тесты CTS проходят с включенным Scudo или без него для данного двоичного файла, чтобы убедиться, что это не влияет на устройство.

Поиск неисправностей

Если обнаружена неустранимая проблема, распределитель отображает сообщение об ошибке в стандартном дескрипторе ошибки, а затем завершает процесс. Трассировки стека, которые приводят к завершению работы, добавляются в системный журнал. Вывод обычно начинается с Scudo ERROR: за ним следует краткое описание проблемы вместе со всеми указателями.

Вот список текущих сообщений об ошибках и их потенциальных причин:

  • corrupted chunk header : проверка контрольной суммы заголовка фрагмента не удалась. Вероятно, это связано с одной из двух причин: заголовок был перезаписан (частично или полностью) или указатель, переданный функции, не является фрагментом.
  • race on chunk header : два разных потока пытаются одновременно манипулировать одним и тем же заголовком. Обычно это является признаком состояния гонки или общего отсутствия блокировки при выполнении операций над этим фрагментом.
  • invalid chunk state : чанк не находится в ожидаемом состоянии для данной операции, например, он не выделяется при попытке освободить его или не помещается в карантин при попытке его перезапустить. Двойное освобождение является типичной причиной этой ошибки.
  • misaligned pointer : строго соблюдаются основные требования к выравниванию: 8 байтов на 32-битных платформах и 16 байтов на 64-битных платформах. Если указатель, переданный нашим функциям, не соответствует им, указатель, переданный одной из функций, не выровнен.
  • allocation type mismatch : если эта опция включена, функция освобождения, вызываемая для фрагмента, должна соответствовать типу функции, которая была вызвана для его выделения. Этот тип несоответствия может привести к проблемам безопасности.
  • invalid sized delete : если используется оператор удаления размера C++14 и включена необязательная проверка, возникает несоответствие между размером, переданным при освобождении фрагмента, и размером, запрошенным при его выделении. Обычно это проблема компилятора или путаница типов освобождаемого объекта.
  • RSS limit exhausted : превышено максимальное значение RSS, указанное дополнительно.

Если вы отлаживаете сбой в самой ОС, вы можете использовать сборку ОС HWASan . Если вы устраняете сбой в приложении, вы также можете использовать сборку приложения HWASan .