Scudo — это динамический распределитель памяти в пользовательском режиме или распределитель кучи , предназначенный для обеспечения устойчивости к уязвимостям, связанным с кучей (таким как переполнение буфера кучи , использование после освобождения и двойное освобождение ) при сохранении производительности. Он предоставляет стандартные примитивы выделения и освобождения C (такие как malloc и free), а также примитивы C++ (такие как new и delete).
Scudo — это скорее средство смягчения, чем полноценный детектор ошибок памяти, такой как AddressSanitizer (ASan) .
Начиная с выпуска Android 11, scudo используется для всего нативного кода (за исключением устройств с малым объемом памяти, где все еще используется jemalloc). Во время выполнения Scudo обслуживает все собственные выделения и освобождения кучи для всех исполняемых файлов и их библиотечных зависимостей, и процесс прерывается, если в куче обнаруживается повреждение или подозрительное поведение.
В Android 10 скудо нужно было включать для каждого двоичного файла, задав параметр LOCAL_SANITIZE := scudo
в файле .mk или параметр sanitize: { scudo: true, }
в файле .bp.
Scudo имеет открытый исходный код и является частью проекта 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 полностью отключает карантин. |
QuarantineChunksUpToSize | 2048 | 512 | Размер (в байтах), до которого фрагменты могут быть помещены в карантин. |
ThreadLocalQuarantineSizeKb | 64 | 16 | Размер (в КБ) кэша каждого потока, используемый для разгрузки глобального карантина. Более низкое значение может уменьшить использование памяти, но может увеличить конкуренцию в глобальном карантине. Установка нуля для этого параметра и QuarantineSizeKb полностью отключает карантин. |
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 .