Как использовать dm-verity в Linux: полное и практическое руководство

  • dm-verity проверяет блоки «на лету» с помощью подписанного корневого хэш-дерева, закрепляя цепочку доверия при загрузке.
  • Его современное развертывание объединяет veritysetup, systemd-veritysetup, Secure Boot и UKI для защиты ядра, initramfs и cmdline.
  • Android использует system-as-root и AVB для передачи параметров dm-verity; FEC и политики реагирования повышают надежность.
  • Неизменяемый корень требует разделения записываемых данных (/var, /home) и планирования обновлений с использованием образов или схем A/B.

dm-verity на Linux

Если вы обеспокоены целостностью своей системы, dm-verity — один из ключевых элементов экосистемы Linux. для безопасной загрузки и обнаружения несанкционированного доступа к хранилищу. Он изначально был частью механизма сопоставления устройств ядра и теперь является основой для верифицированной загрузки в Android, OpenWrt и дистрибутивах, стремящихся к повышению безопасности.

Это не просто абстрактное понятие, dm-verity настраивается и используется с настоящими инструментами, такими как veritysetup и systemd-veritysetupОн проверяет блоки «на лету» с помощью хеш-деревьев и может реагировать на повреждения, применяя различные политики: от регистрации события до перезагрузки или сбоя системы. Давайте рассмотрим это подробнее, не оставляя никаких недочётов.

Что такое dm-verity и почему это может вас заинтересовать

Проверка целостности с помощью dm-verity

dm-verity — это целевой объект сопоставления устройств в ядре, который проверяет целостность блочного устройства при чтении данныхОн работает путем вычисления и проверки хешей каждого блока (обычно 4 КБ) по предварительно вычисленному хеш-дереву, обычно с использованием SHA-256.

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

На Android (начиная с версии 4.4) и Linux в целом, Доверие закреплено в корневом хэше дерева., который подписан и проверен открытым ключом, находящимся в защищённом месте (например, в загрузочном разделе или в подписанном с помощью Secure Boot UKI). Взлом любого блока потребует взлома лежащего в его основе криптографического хеша.

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

Как работает внутреннее дерево проверки

Дерево проверки построено по слоям. Слой 0 — это необработанные данные с устройства, разделенные на блоки по 4 КБ.Для каждого блока вычисляется хеш SHA-256 (с солью). Затем эти хеш-коды объединяются, формируя слой 1. Слой 1 затем группируется в блоки и повторно хешируется, формируя слой 2, и так далее, пока всё не уместится в один блок: этот блок после хеширования создаёт корневой хеш.

Если какой-либо слой не полностью завершает блок, Дополняется нулями до тех пор, пока не достигнет 4К. Чтобы избежать двусмысленности. Общий размер дерева зависит от размера проверяемого раздела; на практике он обычно составляет менее 30 МБ для типичных системных разделов.

Общий процесс таков: выбрать случайную соль, хешировать до 4К, рассчитать SHA-256 с солью по блокам, объединяется для формирования уровней, дополняет границу блока нулями и повторяется с предыдущим уровнем, пока не останется один корневой хеш. Этот корневой хеш вместе с использованной солью поступает в таблицу dm-verity и подпись.

Версии формата диска и алгоритм

Формат хэш-блоков на диске имеет версию. Версия 0 была первоначальной версией, использовавшейся в Chromium OS.: Соль добавляется в конце процесса хеширования, дайджесты сохраняются непрерывно, а оставшаяся часть блока дополняется нулями.

La Версия 1 рекомендуется для новых устройств.: Соль добавляется к хешу, и каждый дайджест дополняется нулями вплоть до степеней двойки, что улучшает выравнивание и надёжность. Таблица dm-verity также указывает алгоритм (например, sha1 или sha256), хотя для текущей безопасности используется sha256.

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

Таблица назначения dm-verity описывает где находятся данные, где находится хэш-дерево и как проверитьТипичные поля таблицы:

  • DEV: устройство с данными для проверки (тип пути /dev/sdXN или больше:меньше).
  • hash_dev: устройство с хэш-деревом (может быть одинаковым; в этом случае hash_start должен находиться за пределами проверяемого диапазона).
  • размер_блока_данных: размер блока данных в байтах (например, 4096).
  • hash_block_size: размер хэш-блока в байтах.
  • num_data_blocks: количество проверяемых блоков данных.
  • hash_start_block: смещение (в блоках hash_block_size) до корневого блока дерева.
  • алгоритм: алгоритм хеширования (например, sha256).
  • дайджест: шестнадцатеричное кодирование хеша корневого блока (включая соль в соответствии с версией формата); этому значению следует доверять.
  • соль: шестнадцатеричная соль.

Кроме того, есть необязательные параметры очень полезно для корректировки поведения:

  • игнорировать_коррупцию: Записывает поврежденные блоки, но позволяет продолжить чтение.
  • перезапуск_при_коррупции: перезапуск при обнаружении повреждения (несовместимо с ignore_corruption и требует поддержки пользовательского пространства для избежания зацикливаний).
  • паника_по_коррупции: : вызывает панику при обнаружении повреждения (несовместимо с предыдущими версиями).
  • перезапуск_при_ошибке y паника_при_ошибке: те же реакции, но для ошибок ввода-вывода.
  • игнорировать_ноль_блоков: не проверяет блоки, которые ожидаются как нули, и возвращает нули.
  • use_fec_from_device + fec_roots + fec_blocks + fec_start: включить алгоритм Рида-Соломона (FEC) для восстановления данных в случае сбоя проверки; области данных, хэша и FEC не должны перекрываться, а размеры блоков должны совпадать.
  • check_at_most_once: проверяет каждый блок данных только при первом чтении (снижает накладные расходы за счет безопасности при активных атаках).
  • root_hash_sig_key_desc: Ссылка на ключ в связке ключей для проверки подписи PKCS7 корневого хеша при создании сопоставления (требуется соответствующая конфигурация ядра и доверенные связки ключей).
  • try_verify_in_tasklet: Если хеши кэшируются и размер ввода-вывода позволяет, проверяет нижнюю половину, чтобы уменьшить задержку; настраивается с помощью /sys/module/dm_verity/parameters/use_bh_bytes для каждого класса ввода-вывода.

Подпись, метаданные и привязка доверия

Чтобы dm-verity был надежным, Корневой хеш должен быть доверенным и обычно подписанным.В классическом Android открытый ключ включен в загрузочный раздел, который проверяется производителем; он проверяет подпись корневого хеша и гарантирует, что системный раздел не был изменен.

Метаданные Verity добавляют структуру и контроль версий. Блок метаданных содержит магическое число 0xb001b001 (байты b0 01 b0 01), версия (в настоящее время 0), подпись таблицы в PKCS1.5 (обычно 256 байт для RSA-2048), длина таблицы, сама таблица и заполнение нулями до 32 КБ.

В реализациях Android проверка основана на fs_mgr и fstab: Добавление галочки к соответствующей записи и размещение ключа в /boot/verity_key. Если магическое число не там, где должно быть, проверка останавливается, чтобы не проверять что-то не то.

Начало работы проверено

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

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

Прямая коррекция ошибок (FEC)

Начиная с Android 7.0, FEC (код Рида-Соломона) интегрирован с методами чересстрочной развертки Для экономии места и повышения возможности восстановления повреждённых блоков. Это работает совместно с dm-verity: если проверка не пройдена, подсистема может попытаться исправить её, прежде чем объявить её невосстановимой.

Производительность и оптимизация

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

Начало работы в Linux (systemd, veritysetup) и Android

Настройка dm-verity на Linux и Android

В современном Linux с systemd, dm-verity позволяет получить проверенный root-доступ только для чтения Используя veritysetup (часть cryptsetup), systemd-veritysetup.generator и systemd-veritysetup@.service. Рекомендуется включить Secure Boot и подписанный UKI (унифицированный образ ядра), хотя это не является обязательным.

Подготовка и рекомендуемое разбиение

Часть функциональной и отлаженной системы. Зарезервировать том для хэш-дерева (8–10% от размера корневого раздела обычно достаточно) и рассмотрите возможность разделения /home и /var, если вам нужно записать данные. Типичная схема включает: ESP (для загрузчика), XBOOTLDR (для UKI), корневой раздел (с шифрованием или без), раздел VERITY и, опционально, /home и /var.

Как корень, EROFS — очень интересная альтернатива ext4 или squashfs.: Он предназначен только для чтения, обладает очень хорошей производительностью на флэш-накопителях/SSD, сжатием lz4 по умолчанию и широко используется на телефонах Android с dm-verity.

Файлы, которые должны быть доступны для записи

С root-ro некоторые программы ожидают записи в /etc или во время инициализацииВы можете переместить его в /var/etc и создать символическую ссылку на всё, что нужно изменить (например, на соединения NetworkManager в /etc/NetworkManager/system-connections). Обратите внимание, что systemd-journald требует наличия /etc/machine-id в корневом каталоге (а не символической ссылки), чтобы избежать сбоев при раннем запуске.

Чтобы узнать, какие изменения произошли в исполнении, использовать dracut-overlayroot: накладывает tmpfs поверх корня, и всё записанное появляется в /run/overlayroot/u. Добавьте модуль в /usr/lib/dracut/modules.d/, включите overlayroot в dracut и установите overlayroot=1 в строке ядра; так вы увидите, что нужно перенести в /var.

Полезные примеры: pacman и NetworkManager

В Арче это удобно Переместите базу данных Pacman в /usr/lib/pacman Чтобы корневая файловая система всегда зеркалировала установленные пакеты. Затем перенаправьте кэш в /var/lib/pacman и скомпонуйте. Чтобы изменить список зеркал, не трогая корневую файловую систему, переместите её в /var/etc и всё равно скомпонуйте.

С NetworkManager, переместить системные соединения в /var/etc/NetworkManager и ссылку из /etc/NetworkManager/system-connections. Это сохраняет корень неизменяемым, а конфигурацию — доступной для записи.

Строительство истины и тестирование

С живого и идеального состояния, смонтированного в RO, создайте дерево и корневой хэш с помощью формат veritysetup: При запуске выводится строка корневого хеша, которую можно сохранить в файл roothash.txt. Запустите его для тестирования командой veritysetup open root-device root verity-device $(cat roothash.txt) и смонтируйте /dev/mapper/root.

Если вы предпочитаете, сначала генерирует дерево в файл (verity.bin) и запишите его в раздел VERITY. Результатом станет: образ корневого раздела, дерево Verity и хеш корневого раздела, который вы закрепите при загрузке.

Настройте линию ядра

Добавьте эти параметры: systemd.verity=1, roothash=contents_of_roothash.txt, systemd.verity_root_data=ROOT-PATH (например, LABEL=OS) и systemd.verity_root_hash=VERITY-PATH (например, LABEL=VERITY). Установите для параметра systemd.verity_root_options значение restart-on-corruption или panic-on-corruption для строгих политик.

Другие рекомендуемые варианты: ro (если вы не используете EROFS/squashfs), rd.emergency=reboot y рд.оболочка=0 (предотвратить запуск неавторизованных оболочек в случае сбоя загрузки) и блокировка=конфиденциальность для защиты памяти ядра от доступа.

Дополнительные разделы с правдой

Не только корень: Вы можете определить другие сопоставления в /etc/veritytab и systemd-veritysetup@.service соберёт их при загрузке. Помните: проще смонтировать в режиме RW некорневой раздел, и пользователь root может отключить Verity на таких разделах, поэтому уровень безопасности там ниже.

Безопасность: безопасная загрузка, UKI и подписанные модули

dm-verity — это не панацея. Подпишите UKI и включите безопасную загрузку с вашими собственными ключами Чтобы предотвратить переопределение kernel/initramfs/cmdline (включая хеш root). Такие инструменты, как sbupdate-git или sbctl, помогают поддерживать подписи образов и целостность цепочки загрузки.

Если вы включите блокировку ядра или проверку подписи модуля, DKMS или модули, не входящие в дерево, должны быть подписаны. иначе они не загрузятся. Рассмотрите возможность использования собственного ядра с поддержкой подписи для вашего конвейера (см. раздел «Подписанные модули ядра»).

Шифрование, TPM и измерение

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

С TPM 2.0, systemd-cryptenroll позволяет привязывать ключи к PCR 0,1,5,7 (прошивка, параметры, GPT, состояние безопасной загрузки). Добавьте rd.luks.options=LUKS_UUID=tpm2-device=auto и обязательно включите поддержку TPM2 в initramfs. systemd-boot измеряет kernel.efi в PCR4, что полезно для отмены ключей при изменении UKI или его командной строки.

Обновления и модели развертывания

Подтвержденный корень, доступный только для чтения Он не обновляется с помощью менеджера пакетов традиционным способом.В идеале нужно создавать новые изображения с помощью таких инструментов, как проект Yocto и опубликовать их. systemd имеет systemd-sysupdate и systemd-repart для надежной загрузки образов и перепрошивки.

Другая стратегия Схема A/B: Вы сохраняете два корня и две версии. Скопируйте активный корень в неактивный, примените изменения и повторите проверку. Вернитесь обратно при следующей загрузке. Если вы используете UKI, не забудьте обновить хеш корня в командной строке или пересобрать подписанный UKI.

Для дополнительной устойчивости, использовать OverlayFS на проверенном корне с верхней частью в tmpfs или на диске. Вы также можете передать systemd.volatile=overlay для временного сохранения. Flatpak упрощает установку приложений в /var и /home, не трогая /.

Существуют автоматизированные пакеты (например, verity-squash-root в AUR), которые создают корень squashfs и подписать roothash с помощью ядра и initramfs, позволяя выбирать между постоянным и временным режимами, а также сохранять последнюю версию rootfs в качестве резервной копии. Примечание: добавление сохранения в проверенный root имеет ограниченные возможности применения; попробуйте сохранять данные приложений на отдельных разделах.

Android: система с правами root, AVB и оверлеи вендора

Начиная с Android 10, RootFS прекращает работу на RAM-диске и интегрируется с system.img. (system-as-root). Устройства с Android 10 всегда используют эту схему и требуют RAM-диск для dm-linear. В этой сборке параметр BOARD_BUILD_SYSTEM_ROOT_IMAGE установлен в значение false, чтобы различать использование RAM-диска и прямую активацию system.img.

Android 10 включает в себя динамические разделы и инициализация первого этапа который активирует логический системный раздел; ядро ​​больше не монтирует его напрямую. Для системных OTA-версий требуется конфигурация «система как root», которая обязательна на устройствах Android 10.

В отсутствие А/Б, хранить восстановление отдельно от загрузкиВ отличие от A/B, резервной копии boot_a/boot_b не существует, поэтому удаление восстановления в режиме, отличном от A/B, может оставить вас без режима восстановления, если обновление загрузки завершится неудачей.

Ядро монтирует system.img в /converity по двум путям: vboot 1.0 (патчи для ядра для анализа метаданных Android в /system и получения параметров dm-verity; командная строка включает root=/dev/dm-0, skip_initramfs и init=/init с dm=…) или vboot 2.0/AVB, где загрузчик интегрирует libavb, считывает дескриптор хэш-дерева (в vbmeta или system), создает параметры и передает их ядру в командной строке с поддержкой FEC и такими флагами, как restart_on_corruption.

С root-системой, не используйте BOARD_ROOT_EXTRA_FOLDERS для корневых папок, специфичных для устройства: они исчезнут при прошивке GSI. Определите конкретные точки монтирования в /mnt/vendor/ , которые fs_mgr создает автоматически, и ссылайтесь на них в fstab дерева устройств.

Android позволяет наложение поставщика из /product/vendor_overlay/: init смонтирует в /vendor подкаталоги, которые соответствуют требованиям контекста SELinux и существованию /vendor/ . Требуется CONFIG_OVERLAY_FS=yy, на старых ядрах — патч override_creds=off.

Типичная реализация: устанавливает предварительно скомпилированные файлы в device/ / /vendor_overlay/, добавьте их в PRODUCT_COPY_FILES с помощью find-copy-subdir-files в $(TARGET_COPY_OUT_PRODUCT)/vendor_overlay, определите контексты в file_contexts для etc и app (например, vendor_configs_file и vendor_app_file) и разрешите mounton для этих контекстов в init.te. Проверьте с помощью atest vfs_mgr_vendor_overlay_test в userdebug.

Устранение неполадок: сообщение о повреждении dm-verity на Android

На устройствах со слотами A/B измените слоты или Перепрошивка vbmeta/boot без согласованности с roothash Это может вызвать предупреждение: «dm-verity damaged, ваше устройство не является доверенным». Команды типа fastboot flash –disable-verity –disable-verification vbmeta vbmeta.img отключают проверку, но оставляют систему без каких-либо гарантий целостности.

Некоторые загрузчики поддерживают fastboot oem disable_dm_verity и его противоположность, enable_dm_verity. Работает на некоторых моделях, но не на других; может потребоваться ядро/magisk с измененными флагами. Используйте на свой страх и риск: разумный подход: выровнять загрузку, vbmeta и систему, подпишите или пересоздайте дерево и убедитесь, что ожидаемый корневой хэш соответствует настроенному.

Если после предупреждения вы можете продолжать нажимать кнопку питания, система запустится, но у вас больше нет целостной цепочки доверияЧтобы удалить сообщение, не жертвуя безопасностью, восстановите исходные подписанные изображения или перестройте/проверьте vbmeta с правильным хэш-деревом вместо отключения verity.

платформы i.MX и OpenWrt

На i.MX6 (например, sabresd), настроить ядро ​​с поддержкой DM_VERITY и FEC, сгенерируйте дерево с помощью veritysetup, безопасно сохраните хеш корня и передайте соответствующие параметры в командной строке или интегрируйте через initramfs с помощью systemd-veritysetup. Если вы не используете dm-crypt, вам не нужен CAAM для verity; основное внимание уделяется целостности.

В OpenWrt и в встраиваемые системы Linux с OpenEmbedded, Предпринимаются попытки интегрировать dm-verity и SELinux. (Задания Bootlin пересмотрены с целью включения поддержки.) Это естественное решение: маршрутизаторы и сетевое оборудование получают преимущества от неизменяемого, проверенного и защищённого MAC-адреса корневого сертификата.

Ручное построение дерева и метаданных (подробный просмотр)

cryptsetup может сгенерировать дерево для вас, но если вы предпочитаете понять формат, определение строки компактной таблицы включает в себя: имя сопоставления, устройство данных, размеры блока данных и хеша, размер изображения в блоках, позиция hash_start (изображение блока + 8, если объединено), корневой хеш и соль. После создания объединенных слоев (сверху вниз, за ​​исключением слоя 0) дерево записывается на диск.

Чтобы все упаковать, составить таблицу dm-verity, подписать ее (обычно RSA-2048) и сгруппировать подпись+таблицу в метаданных с версионированным заголовком и магическим числом. Затем он объединяет образ системы, метаданные verity и хэш-дерево. В fstab он помечает fs_mgr как проверочный и помещает открытый ключ в /boot/verity_key для проверки подписи.

Оптимизировать с помощью Ускорение SHA-2 для вашего процессора и настроить упреждающее чтение/prefetch_cluster. На оборудовании ARM NEON SHA-2 (ARMv7) и расширения SHA-2 (ARMv8) значительно снижают накладные расходы на проверку.

При любом развертывании помните, что значение корневого хеша должно быть защищено: независимо от того, скомпилирован ли он в подписанный UKI, в подписанный загрузочный раздел или проверен загрузчиком с помощью AVB. Всё последующее наследует это доверие.

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

Что такое проект Yocto?
Теме статьи:
Что такое Yocto Project: полное встроенное руководство

Добавить в качестве предпочтительного источника