Google 致力于为黑人社区推动种族平等。查看具体举措
Эта страница переведена с помощью Cloud Translation API.
Switch to English

Реализация dm-verity

Android 4.4 и выше поддерживает проверенную загрузку с помощью дополнительной функции ядра device-mapper-verity (dm-verity), которая обеспечивает прозрачную проверку целостности блочных устройств. dm-verity помогает предотвратить постоянные руткиты, которые могут удерживать root-права и компрометировать устройства. Эта функция помогает пользователям Android быть уверенными, что при загрузке устройство находится в том же состоянии, в котором оно использовалось в последний раз.

Потенциально опасные приложения (PHA) с привилегиями root могут скрываться от программ обнаружения и иным образом маскироваться. Программное обеспечение для рутинга может это делать, потому что оно часто имеет более высокий уровень привилегий, чем детекторы, что позволяет программному обеспечению «лгать» программам обнаружения.

Функция dm-verity позволяет вам посмотреть на блочное устройство, базовый уровень хранения файловой системы, и определить, соответствует ли оно ожидаемой конфигурации. Он делает это с помощью криптографического хеш-дерева. Для каждого блока (обычно 4k) есть хэш SHA256.

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

dm-verity-hash-таблица

Рисунок 1. Хеш-таблица dm-verity

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

Операция

Защита dm-verity живет в ядре. Таким образом, если рутованное программное обеспечение компрометирует систему до того, как ядро ​​заработает, оно сохранит этот доступ. Чтобы уменьшить этот риск, большинство производителей проверяют ядро, используя ключ, записанный в устройство. Этот ключ нельзя изменить после того, как устройство покинет завод.

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

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

Вместо этого dm-verity проверяет блоки индивидуально и только при обращении к каждому из них. При чтении в память блок хешируется параллельно. Затем хэш проверяется на дереве. А поскольку чтение блока - такая дорогостоящая операция, задержка, вносимая этой проверкой на уровне блока, является сравнительно номинальной.

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

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

Прямое исправление ошибок

Android 7.0 и выше улучшает устойчивость dm-verity с прямым исправлением ошибок (FEC). Реализация AOSP начинается с общего кода исправления ошибок Рида-Соломона и применяет метод, называемый чередованием, для уменьшения накладных расходов на пространство и увеличения количества поврежденных блоков, которые могут быть восстановлены. Дополнительные сведения о FEC см. В разделе Строго принудительная проверенная загрузка с исправлением ошибок .

Реализация

Резюме

  1. Создайте образ системы ext4.
  2. Создайте хеш-дерево для этого изображения.
  3. Создайте таблицу dm-verity для этого хеш-дерева.
  4. Подпишите эту таблицу dm-verity, чтобы получить подпись таблицы.
  5. Объедините подпись таблицы и таблицу dm-verity в метаданные verity.
  6. Объедините образ системы, метаданные истинности и хеш-дерево.

См.«Проекты Chromium - Проверенная загрузка» для получения подробного описания хэш-дерева и таблицы dm-verity.

Генерация хеш-дерева

Как описано во введении, хеш-дерево является неотъемлемой частью dm-verity. Инструмент cryptsetup сгенерирует для вас хеш-дерево. В качестве альтернативы здесь определяется совместимый:

<your block device name> <your block device name> <block size> <block size> <image size in blocks> <image size in blocks + 8> <root hash> <salt>

Для формирования хэша системный образ разделяется на уровне 0 на 4k блоков, каждому из которых назначается хэш SHA256. Уровень 1 формируется путем объединения только этих хэшей SHA256 в блоки размером 4 КБ, в результате чего изображение намного меньше. Уровень 2 сформирован идентично с хэшами SHA256 уровня 1.

Это делается до тех пор, пока хэши SHA256 предыдущего слоя не поместятся в один блок. Когда вы получаете SHA256 этого блока, у вас есть корневой хеш дерева.

Размер хеш-дерева (и соответствующее использование дискового пространства) зависит от размера проверенного раздела. На практике размер хеш-деревьев обычно невелик, часто менее 30 МБ.

Если у вас есть блок в слое, который не полностью заполнен естественным образом хэшами предыдущего слоя, вы должны заполнить его нулями, чтобы получить ожидаемые 4k. Это позволяет узнать, что хэш-дерево не было удалено, а вместо этого заполнено пустыми данными.

Чтобы сгенерировать хеш-дерево, объедините хэши уровня 2 с хешами для уровня 1, хеши уровня 3 с хешами уровня 2 и так далее. Запишите все это на диск. Обратите внимание, что это не относится к уровню 0 корневого хеша.

Напомним, общий алгоритм построения хэш-дерева выглядит следующим образом:

  1. Выберите случайную соль (шестнадцатеричная кодировка).
  2. Разбейте образ вашей системы на блоки размером 4К.
  3. Для каждого блока получите свой (соленый) хеш SHA256.
  4. Объедините эти хэши, чтобы сформировать уровень
  5. Заполните уровень от 0 до границы блока 4k.
  6. Свяжите уровень со своим хеш-деревом.
  7. Повторите шаги 2–6, используя предыдущий уровень в качестве источника для следующего, пока у вас не будет только один хэш.

Результатом этого является единственный хеш, который является вашим корневым хешем. Это и ваша соль используются при построении вашей таблицы сопоставления dm-verity.

Построение таблицы сопоставления dm-verity

Создайте таблицу сопоставления dm-verity, которая идентифицирует блочное устройство (или цель) для ядра и расположение хэш-дерева (которое имеет одно и то же значение). Это сопоставление используется для создания и загрузки fstab . В таблице также указывается размер блоков и hash_start, начальное положение хэш-дерева (в частности, номер его блока от начала изображения).

См. Cryptsetup для подробного описания полей таблицы сопоставления цели verity.

Подписание таблицы dm-verity

Подпишите таблицу dm-verity, чтобы создать подпись таблицы. При проверке раздела сначала проверяется подпись таблицы. Это делается для ключа на вашем загрузочном образе в фиксированном месте. Ключи обычно включаются в системы сборки производителей для автоматического включения в устройства в фиксированном месте.

Чтобы проверить раздел с этой подписью и комбинацией клавиш:

  1. Добавьте ключ RSA-2048 в формате, совместимом с libmincrypt, в раздел /boot адресу /verity_key . Определите расположение ключа, используемого для проверки хеш-дерева.
  2. В Fstab для соответствующей записи, добавить verify в fs_mgr флагов.

Объединение подписи таблицы в метаданные

Объедините подпись таблицы и таблицу dm-verity в метаданные verity. Весь блок метаданных версируется, поэтому он может быть расширен, например, для добавления второго типа подписи или изменения некоторого порядка.

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

Это гарантирует, что вы не выбрали подтверждение непроверенного раздела. Если да, то отсутствие этого магического числа остановит процесс проверки. Этот номер похож на:
0xb001b001

Значения байтов в шестнадцатеричном формате:

  • первый байт = b0
  • второй байт = 01
  • третий байт = b0
  • четвертый байт = 01

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

<magic number>|<version>|<signature>|<table length>|<table>|<padding>
\-------------------------------------------------------------------/
\----------------------------------------------------------/   |
                            |                                  |
                            |                                 32K
                       block content

И эта таблица описывает эти поля метаданных.

Таблица 1. Поля метаданных Verity

Поле Цель Размер Значение
магическое число используется fs_mgr как проверка работоспособности 4 байта 0xb001b001
версия используется для версии блока метаданных 4 байта в настоящее время 0
подпись подпись таблицы в дополненной форме PKCS1.5 256 байт
длина стола длина таблицы dm-verity в байтах 4 байта
Таблица таблица dm-verity, описанная ранее длина таблицы в байтах
набивка эта структура дополнена нулями до 32k в длину 0

Оптимизация dm-verity

Чтобы получить максимальную производительность от dm-verity, вам следует:

  • В ядре включите NEON SHA-2 для ARMv7 и расширения SHA-2 для ARMv8.
  • Поэкспериментируйте с различными настройками упреждающего чтения и prefetch_cluster, чтобы найти лучшую конфигурацию для вашего устройства.