UndefinedBehaviorSanitizer

UndefineBehaviorSanitizer (UBSan) выполняет инструментирование во время компиляции для проверки различных типов неопределенного поведения. Хотя UBSan способен обнаруживать множество неопределенных ошибок поведения , Android поддерживает:

  • выравнивание
  • логическое значение
  • границы
  • перечисление
  • переполнение с плавающей запятой
  • деление на ноль с плавающей запятой
  • целое число, деление на ноль
  • ненулевой атрибут
  • нулевой
  • возвращаться
  • возвращает ненулевой атрибут
  • сменная база
  • показатель сдвига
  • целочисленное переполнение со знаком
  • недостижимый
  • беззнаковое-целочисленное переполнение
  • вла-связанный

unsigned-integer-overflow, хотя технически и не является неопределенным поведением, включен в дезинфицирующее средство и используется во многих модулях Android, включая компоненты медиасервера, для устранения любых скрытых уязвимостей переполнения целых чисел.

Выполнение

В системе сборки Android вы можете включить UBSan глобально или локально. Чтобы включить UBSan глобально, установите SANITIZE_TARGET в Android.mk. Чтобы включить UBSan на уровне каждого модуля, установите LOCAL_SANITIZE и укажите неопределенное поведение, которое вы хотите искать в Android.mk. Например:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)

LOCAL_CFLAGS := -std=c11 -Wall -Werror -O0

LOCAL_SRC_FILES:= sanitizer-status.c

LOCAL_MODULE:= sanitizer-status

LOCAL_SANITIZE := alignment bounds null unreachable integer
LOCAL_SANITIZE_DIAG := alignment bounds null unreachable integer

include $(BUILD_EXECUTABLE)

И эквивалентная конфигурация проекта (Android.bp):

cc_binary {

    cflags: [
        "-std=c11",
        "-Wall",
        "-Werror",
        "-O0",
    ],

    srcs: ["sanitizer-status.c"],

    name: "sanitizer-status",

    sanitize: {
        misc_undefined: [
            "alignment",
            "bounds",
            "null",
            "unreachable",
            "integer",
        ],
        diag: {
            misc_undefined: [
                "alignment",
                "bounds",
                "null",
                "unreachable",
                "integer",
            ],
        },
    },

}

Ярлыки UBSan

В Android также есть два ярлыка, integer и default-ub , для одновременного включения набора дезинфицирующих средств. целое число включает integer-divide-by-zero , signed-integer-overflow и unsigned-integer-overflow . default-ub включает проверки, которые имеют минимальные проблемы с производительностью компилятора: bool, integer-divide-by-zero, return, returns-nonnull-attribute, shift-exponent, unreachable and vla-bound . Класс целочисленного дезинфицирующего средства можно использовать с SANITIZE_TARGET и LOCAL_SANITIZE, тогда как default-ub можно использовать только с SANITIZE_TARGET.

Лучшее сообщение об ошибках

Реализация UBsan в Android по умолчанию вызывает указанную функцию при обнаружении неопределенного поведения. По умолчанию эта функция прерывается. Однако, начиная с октября 2016 года, UBSan для Android имеет дополнительную библиотеку времени выполнения, которая предоставляет более подробные отчеты об ошибках, включая тип обнаруженного неопределенного поведения, информацию о файле и строках исходного кода. Чтобы включить отчет об ошибках с целочисленными проверками, добавьте в файл Android.mk следующее:

LOCAL_SANITIZE:=integer
LOCAL_SANITIZE_DIAG:=integer

Значение LOCAL_SANITIZE включает дезинфицирующее средство во время сборки. LOCAL_SANITIZE_DIAG включает режим диагностики для указанного дезинфицирующего средства. Можно установить для LOCAL_SANITIZE и LOCAL_SANITIZE_DIAG разные значения, но включены только проверки в LOCAL_SANITIZE. Если проверка не указана в LOCAL_SANITIZE, но указана в LOCAL_SANITIZE_DIAG, проверка не включена и диагностические сообщения не выдаются.

Вот пример информации, предоставляемой библиотекой времени выполнения UBSan:

pixel-xl:/ # sanitizer-status ubsan
sanitizer-status/sanitizer-status.c:53:6: runtime error: unsigned integer overflow: 18446744073709551615 + 1 cannot be represented in type 'size_t' (aka 'unsigned long')

Очистка целочисленного переполнения

Непреднамеренное переполнение целых чисел может привести к повреждению памяти или уязвимостям раскрытия информации в переменных, связанных с доступом к памяти или ее выделением. Чтобы бороться с этим, мы добавили средства очистки знакового и беззнакового целочисленного переполнения UndefinedBehaviorSanitizer (UBSan) от Clang, чтобы укрепить медиа-фреймворк в Android 7.0. В Android 9 мы расширили UBsan, включив в него больше компонентов , и улучшили поддержку системы сборки.

Это предназначено для добавления проверок арифметических операций/инструкций, которые могут переполниться, чтобы безопасно прервать процесс, если переполнение все же произойдет. Эти дезинфицирующие средства могут смягчить целый класс уязвимостей, связанных с повреждением памяти и раскрытием информации, основной причиной которых является целочисленное переполнение, например, оригинальная уязвимость Stagefright.

Примеры и источник

Очистка целочисленного переполнения (IntSan) предоставляется компилятором и добавляет инструменты в двоичный файл во время компиляции для обнаружения арифметических переполнений. Он включен по умолчанию в различных компонентах платформы, например /platform/external/libnl/Android.bp .

Выполнение

IntSan использует средства очистки знакового и беззнакового целочисленного переполнения UBSan. Это смягчение включено на уровне каждого модуля. Это помогает обеспечить безопасность критически важных компонентов Android, и его не следует отключать.

Мы настоятельно рекомендуем вам включить очистку целочисленного переполнения для дополнительных компонентов. Идеальными кандидатами являются привилегированный собственный код или собственный код, который анализирует ненадежный пользовательский ввод. С дезинфицирующим средством связано небольшое снижение производительности, которое зависит от использования кода и распространенности арифметических операций. Ожидайте небольшой процент накладных расходов и проверьте, является ли производительность проблемой.

Поддержка IntSan в make-файлах

Чтобы включить IntSan в make-файле, добавьте:

LOCAL_SANITIZE := integer_overflow
    # Optional features
    LOCAL_SANITIZE_DIAG := integer_overflow
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt
  • LOCAL_SANITIZE принимает список дезинфицирующих средств, разделенных запятыми, причем integer_overflow представляет собой предварительно упакованный набор опций для отдельных дезинфицирующих средств переполнения целых чисел со знаком и без знака со значением BLOCKLIST по умолчанию .
  • LOCAL_SANITIZE_DIAG включает режим диагностики для дезинфицирующих средств. Используйте режим диагностики только во время тестирования, поскольку он не будет прерываться при переполнении, что полностью сводит на нет преимущества безопасности, связанные с устранением последствий. Дополнительные сведения см. в разделе «Устранение неполадок» .
  • LOCAL_SANITIZE_BLOCKLIST позволяет вам указать файл BLOCKLIST, чтобы предотвратить очистку функций и исходных файлов. Дополнительные сведения см. в разделе «Устранение неполадок» .

Если вам нужен более детальный контроль, включите дезинфицирующие средства по отдельности, используя один или оба флага:

LOCAL_SANITIZE := signed-integer-overflow, unsigned-integer-overflow
    LOCAL_SANITIZE_DIAG := signed-integer-overflow, unsigned-integer-overflow

Поддержка IntSan в файлах чертежей

Чтобы включить очистку целочисленного переполнения в файле схемы, например /platform/external/libnl/Android.bp , добавьте:

   sanitize: {
          integer_overflow: true,
          diag: {
              integer_overflow: true,
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

Как и в случае с файлами make, свойство integer_overflow представляет собой предварительно упакованный набор опций для отдельных дезинфицирующих средств целочисленного переполнения со знаком и без знака со значением BLOCKLIST по умолчанию .

Набор свойств diag включает режим диагностики для дезинфицирующих средств. Используйте режим диагностики только во время тестирования. Режим диагностики не прерывается при переполнении, что полностью сводит на нет преимущества безопасности, связанные со смягчением последствий в пользовательских сборках. Дополнительные сведения см. в разделе «Устранение неполадок» .

Свойство BLOCKLIST позволяет указать файл BLOCKLIST, который позволяет разработчикам предотвращать очистку функций и исходных файлов. Дополнительные сведения см. в разделе «Устранение неполадок» .

Чтобы включить дезинфицирующие средства по отдельности, используйте:

   sanitize: {
          misc_undefined: ["signed-integer-overflow", "unsigned-integer-overflow"],
          diag: {
              misc_undefined: ["signed-integer-overflow",
                               "unsigned-integer-overflow",],
          },
          BLOCKLIST: "modulename_BLOCKLIST.txt",
       },

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

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

Чтобы найти прерывания, вызванные очисткой в ​​пользовательских сборках, найдите сбои SIGABRT с сообщениями об аварийном прекращении, указывающими на переполнение, обнаруженное UBSan, например:

pid: ###, tid: ###, name: Binder:###  >>> /system/bin/surfaceflinger <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: sub-overflow'

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

Чтобы упростить определение основной причины, включите диагностику в библиотеке, вызывающую прерывание, и попытайтесь воспроизвести ошибку. Если диагностика включена, процесс не прервется , а продолжит работать. Отсутствие прерывания помогает максимизировать количество безопасных переполнений на конкретном пути выполнения без необходимости перекомпиляции после исправления каждой ошибки. Диагностика выдает сообщение об ошибке, которое включает номер строки и исходный файл, вызывающий прерывание:

frameworks/native/services/surfaceflinger/SurfaceFlinger.cpp:2188:32: runtime error: unsigned integer overflow: 0 - 1 cannot be represented in type 'size_t' (aka 'unsigned long')

Как только проблемная арифметическая операция обнаружена, убедитесь, что переполнение является безопасным и намеренным (например, не имеет последствий для безопасности). Вы можете устранить отмену дезинфицирующего средства следующим образом:

  • Рефакторинг кода во избежание переполнения ( пример )
  • Переполнение явно через функции __builtin__*_overflow в Clang ( пример )
  • Отключение санации в функции путем указания атрибута no_sanitize ( пример )
  • Отключение очистки функции или исходного файла через файл BLOCKLIST ( пример )

Вам следует использовать максимально детальное решение. Например, в большой функции со многими арифметическими операциями и одной операцией переполнения следует провести рефакторинг одной операции, а не помещать в BLOCKLIST всю функцию.

Общие закономерности, которые могут привести к доброкачественным переполнениям, включают:

  • Неявное приведение типов , при котором происходит беззнаковое переполнение перед приведением к знаковому типу ( пример )
  • Удаление связанного списка, которое уменьшает индекс цикла при удалении ( пример )
  • Присвоение беззнакового типа значению -1 вместо указания фактического максимального значения ( пример )
  • Циклы, которые уменьшают целое число без знака в условии ( пример , пример )

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

Отключение ИнтСан

Вы можете отключить IntSan с помощью BLOCKLIST или атрибутов функции. Отключайте с осторожностью и только в том случае, если рефакторинг кода необоснован или если возникают проблемы с производительностью.

Дополнительную информацию об отключении IntSan с помощью атрибутов функций и форматировании файлов BLOCKLIST см. в документации по вышестоящему продукту Clang. BLOCKLISTing должен быть ограничен конкретным дезинфицирующим средством, используя имена разделов, указывающие целевое дезинфицирующее средство, чтобы избежать влияния на другие дезинфицирующие средства.

Проверка

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

Дезинфекция границ

BoundsSanitizer (BoundSan) добавляет к двоичным файлам инструменты для вставки проверок границ при доступе к массиву. Эти проверки добавляются, если компилятор не может доказать во время компиляции, что доступ будет безопасным, и если размер массива будет известен во время выполнения, чтобы его можно было проверить. Android 10 использует BoundSan в Bluetooth и кодеках. BoundSan предоставляется компилятором и включен по умолчанию в различных компонентах платформы.

Выполнение

BoundSan использует дезинфицирующее средство для границ UBSan . Это смягчение включено на уровне каждого модуля. Это помогает обеспечить безопасность критически важных компонентов Android, и его нельзя отключать.

Мы настоятельно рекомендуем вам включить BoundSan для дополнительных компонентов. Идеальными кандидатами являются привилегированный машинный код или сложный машинный код, который анализирует ненадежный пользовательский ввод. Накладные расходы на производительность, связанные с включением BoundSan, зависят от количества обращений к массиву, безопасность которых не может быть доказана. Ожидайте в среднем небольшой процент накладных расходов и проверьте, является ли производительность проблемой.

Включение BoundSan в файлах чертежей

BoundSan можно включить в файлах чертежей, добавив "bounds" к свойству санитизации misc_undefined для двоичных и библиотечных модулей:

    sanitize: {
       misc_undefined: ["bounds"],
       diag: {
          misc_undefined: ["bounds"],
       },
       BLOCKLIST: "modulename_BLOCKLIST.txt",
Диагностика

Свойство diag включает режим диагностики для дезинфицирующих средств. Используйте режим диагностики только во время тестирования. Режим диагностики не прерывается при переполнении, что сводит на нет преимущества безопасности, связанные с устранением последствий, и приводит к более высоким затратам производительности, поэтому его не рекомендуется использовать для производственных сборок.

ЧЕРНЫЙ СПИСОК

Свойство BLOCKLIST позволяет указать файл BLOCKLIST, который разработчики могут использовать для предотвращения очистки функций и исходных файлов. Используйте это свойство только в том случае, если производительность вызывает беспокойство и целевые файлы/функции вносят существенный вклад. Вручную проверяйте эти файлы/функции, чтобы гарантировать безопасность доступа к массиву. Дополнительные сведения см. в разделе «Устранение неполадок» .

Включение BoundSan в make-файлах

BoundSan можно включить в make-файлах, добавив "bounds" к переменной LOCAL_SANITIZE для бинарных и библиотечных модулей:

    LOCAL_SANITIZE := bounds
    # Optional features
    LOCAL_SANITIZE_DIAG := bounds
    LOCAL_SANITIZE_BLOCKLIST := modulename_BLOCKLIST.txt

LOCAL_SANITIZE принимает список дезинфицирующих средств, разделенных запятой.

LOCAL_SANITIZE_DIAG включает режим диагностики. Используйте режим диагностики только во время тестирования. Режим диагностики не прерывается при переполнении, что сводит на нет преимущества безопасности, связанные с устранением последствий, и приводит к более высоким затратам производительности, поэтому его не рекомендуется использовать для производственных сборок.

LOCAL_SANITIZE_BLOCKLIST позволяет указать файл BLOCKLIST, который позволяет разработчикам предотвращать очистку функций и исходных файлов. Используйте это свойство только в том случае, если производительность вызывает беспокойство и целевые файлы/функции вносят существенный вклад. Вручную проверяйте эти файлы/функции, чтобы гарантировать безопасность доступа к массиву. Дополнительные сведения см. в разделе «Устранение неполадок» .

Отключение BoundSan

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

Дополнительную информацию об отключении BoundSan с помощью атрибутов функций и форматировании файлов BLOCKLIST см. в документации Clang LLVM. Охватите BLOCKLISTing конкретным дезинфицирующим средством, используя имена разделов, указывающие целевое дезинфицирующее средство, чтобы избежать влияния на другие дезинфицирующие средства.

Проверка

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

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

Тщательно протестируйте компоненты после включения BoundSan, чтобы убедиться, что все ранее необнаруженные внешние доступы устранены.

Ошибки BoundSan можно легко идентифицировать, поскольку они включают в себя следующее сообщение о прекращении захоронения:

    pid: ###, tid: ###, name: Binder:###  >>> /system/bin/foobar <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'ubsan: out-of-bounds'

При работе в режиме диагностики исходный файл, номер строки и значение индекса выводятся в logcat . По умолчанию этот режим не выдает сообщение об отмене. Просмотрите logcat , чтобы проверить наличие ошибок.

    external/foo/bar.c:293:13: runtime error: index -1 out of bounds for type 'int [24]'