
Ако сте загрижени за целостта на вашата система, dm-verity е един от ключовите елементи на екосистемата на Linux. за безопасно зареждане и откриване на промяна на паметта. Той произхожда като част от инструмента за картографиране на устройства на ядрото и сега е основата за проверено зареждане в Android, OpenWrt и дистрибуции, търсещи подобрена сигурност.
Далеч от това да е абстрактно понятие, dm-verity се конфигурира и използва с реални инструменти като veritysetup и systemd-veritysetupТой валидира блокове в движение, използвайки хеш дървета, и може да реагира на корупция с политики, вариращи от регистриране на събитието до рестартиране или срив на системата. Нека разгледаме по-отблизо, без да оставяме никакви недоразумения.
Какво е dm-verity и защо може да ви е грижа
dm-verity е целева програма за мапиране на устройства в ядрото, която проверява целостта на блоковото устройство при четене на данниРаботи чрез изчисляване и проверка на хешовете на всеки блок (обикновено 4K) спрямо предварително изчислено хеш дърво, обикновено използващо SHA-256.
Този дизайн позволява Файловете не могат да бъдат променяни тихомълком между рестартирания или по време на изпълнениеТова е ключово за разширяване на веригата на доверие при зареждане към операционната система, ограничаване на устойчивостта на зловреден софтуер, засилване на политиките за сигурност и осигуряване на криптиране и MAC механизми по време на зареждане.
В Android (от версия 4.4) и Linux като цяло, Доверието е закотвено в коренния хеш на дървото, който е подписан и валидиран с публичен ключ, разположен на защитено място (напр. на boot дяла или в Secure Boot-signed UKI). Разбиването на който и да е блок би изисквало разбиване на основния криптографски хеш.
Проверката се извършва по блок и при поискване: Добавената латентност е минимална в сравнение с разходите за входно/изходни операции.Ако проверката е неуспешна, ядрото връща грешка при входно/изходни операции и файловата система изглежда повредена, което е очаквано, когато данните са ненадеждни. Приложенията могат да решат дали да продължат или не въз основа на своята отказоустойчивост.
Как работи дървото за проверка вътрешно
Дървото на проверката е изградено на слоеве. Слой 0 е суровите данни от устройството, разделени на 4K блокове.; за всеки блок се изчислява SHA-256 (salted) хеш. След това тези хешове се конкатенират, за да образуват слой 1. След това слой 1 се групира в блокове и се хешира отново, за да образува слой 2, и така нататък, докато всичко се побере в един блок: този блок, когато се хешира, произвежда коренния хеш.
Ако някой слой не завършва точно блок, Допълва се с нули, докато достигне 4K за да се избегне неяснота. Общият размер на дървото зависи от размера на проверявания дял; на практика той обикновено е по-малък от 30 MB за типичните системни дялове.
Общият процес е: изберете произволна сол, хеширайте до 4K, изчислете SHA-256 със сол за блок, конкатенира се, за да образува нива, допълва границата на блока с нули и повтаря с предишното ниво, докато не остане един-единствен коренен хеш. Този коренен хеш, заедно с използваната сол (salt), захранва таблицата dm-verity и сигнатурата.
Версии на дисков формат и алгоритъм
Форматът на хеш блоковете на диска има версия. Версия 0 беше оригиналната версия, използвана в Chromium OS.Солта се добавя в края на процеса на хеширане, дайджестите се съхраняват непрекъснато, а останалата част от блока се допълва с нули.
La Версия 1 се препоръчва за нови устройстваСолтта се добавя към хеша и всеки дайджест се допълва с нули до степени на две, подобрявайки подравняването и устойчивостта. Таблицата dm-verity също така определя алгоритъма (напр. sha1 или sha256), въпреки че за текуща сигурност се използва sha256.
dm-verity таблица и основни параметри
Целевата таблица dm-verity описва къде са данните, къде е хеш дървото и как да се провериТипични полета на таблицата:
- Дев: устройство с данните, които ще бъдат проверени (тип път /dev/sdXN или по-голям:по-малък).
- hash_dev: устройство с хеш дървото (може да е същото; ако е така, hash_start трябва да е извън проверения диапазон).
- размер_на_блок_данни: размер на блока данни в байтове (напр. 4096).
- размер_на_хеш_блок: размер на хеш блока в байтове.
- брой_блокове_данни: брой проверими блокове данни.
- хеш_стартов_блок: отместване (в блокове hash_block_size) спрямо коренния блок на дървото.
- алгоритъм: хеш алгоритъм (напр. sha256).
- резюме: шестнадесетично кодиране на хеша на коренния блок (включително солта според версията на формата); на тази стойност трябва да се има доверие.
- солшестнадесетична сол.
Освен това има незадължителни параметри много полезно за коригиране на поведението:
- игнориране на корупциятаЗаписва повредени блокове, но позволява четенето да продължи.
- рестартиране_при_корупция: рестартиране при откриване на повреда (не е съвместимо с ignore_corruption и изисква поддръжка от потребителското пространство, за да се избегнат цикли).
- паника_срещу_корупцията: : причинява паника при откриване на повреда (не е съвместимо с предишни версии).
- рестартиране_при_грешка y паника_при_грешка: същите реакции, но за входно/изходни грешки.
- игнориране на нула блокове: не проверява блокове, които се очакват като нули, и връща нули.
- използване_фек_от_устройството + fec_roots + fec_блокове + fec_start: Активирайте Reed-Solomon (FEC) метода за възстановяване на данни, когато проверката е неуспешна; областите с данни, хеш и FEC не трябва да се припокриват и размерите на блоковете трябва да съвпадат.
- провери_най-много_веднъжПроверява всеки блок данни само при първото му четене (намалява разходите за сметка на сигурността при атаки на живо).
- описание на root_hash_sig_key: Препратка към ключ в ключовете за валидиране на PKCS7 подпис на главния хеш при създаване на съпоставянето (изисква подходяща конфигурация на ядрото и надеждни ключове).
- try_verify_in_taskletАко хешовете са кеширани и размерът на I/O позволява, проверява долната половина, за да се намали латентността; коригирано с /sys/module/dm_verity/parameters/use_bh_bytes за всеки I/O клас.
Подпис, метаданни и закотвяне на доверие
За да бъде dm-verity надежден, Коренният хеш трябва да е надежден и обикновено подписан.В класическия Android, в дяла за зареждане е включен публичен ключ, който се проверява външно от производителя; той валидира коренния хеш подпис и гарантира, че системният дял не е бил променен.
Метаданните на Verity добавят структура и контрол на версиите. Блокът с метаданни включва магическо число 0xb001b001 (байтове b0 01 b0 01), версия (в момента 0), сигнатурата на таблицата в PKCS1.5 (обикновено 256 байта за RSA-2048), дължината на таблицата, самата таблица и допълване с нули до 32K.
В Android реализациите, проверката разчита на fs_mgr и fstabДобавяне на отметка към съответния запис и поставяне на ключа в /boot/verity_key. Ако магическото число не е там, където трябва да бъде, проверката спира, за да се избегне проверка на грешно нещо.
Стартирането на операцията е потвърдено
Защитата е вградена в ядрото: Ако бъде компрометирана преди зареждане на ядрото, атакуващият запазва контролЕто защо производителите обикновено стриктно валидират всеки етап: ключ, записан в устройството, проверява първия буутлоудър, който проверява следващия - буутлоудъра на приложението и накрая - ядрото.
След като ядрото е проверено, dm-verity е активиран при монтиране на провереното блоково устройствоВместо да се хешира цялото устройство (което би било бавно и би хабило енергия), то се проверява блок по блок при достъп. Неуспехът причинява I/O грешка, а услугите и приложенията реагират според своята толерантност: или продължават без тези данни, или се сриват напълно.
Корекция на грешките напред (FEC)
От Android 7.0, FEC (Reed-Solomon) е включен в техниките за преплитане за намаляване на пространството и увеличаване на възможността за възстановяване на повредени блокове. Това работи съвместно с dm-verity: ако проверката е неуспешна, подсистемата може да се опита да я коригира, преди да я обяви за невъзстановима.
Ефективност и оптимизация
За да се намали въздействието: Активиране на SHA-2 ускорение от NEON на ARMv7 и SHA-2 разширения на ARMv8 от ядрото. Настройте параметрите за предварително четене и prefetch_cluster за вашия хардуер; проверката на блок обикновено добавя малко към разходите за входно/изходни операции, но тези настройки имат значение.
Първи стъпки в Linux (systemd, veritysetup) и Android
На съвременен Linux със systemd, dm-verity позволява проверен root само за четене използвайки veritysetup (част от cryptsetup), systemd-veritysetup.generator и systemd-veritysetup@.service. Препоръчително е да включите Secure Boot и подписан UKI (унифициран образ на ядрото), въпреки че не са строго задължителни.
Подготовка и препоръчително разделяне
Част от функционална и настроена система. Резервирайте обем за хеш дървото (8–10% от размера на root директорията обикновено е достатъчно) и помислете за разделяне на /home и /var, ако е необходимо да пишете. Типична схема включва: ESP (за bootloader-а), XBOOTLDR (за UKI), root (със или без криптиране), 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 върху root-а и всичко записано се появява в /run/overlayroot/u. Добавете модула към /usr/lib/dracut/modules.d/, включете overlayroot в dracut и задайте overlayroot=1 на реда за ядрото; по този начин ще видите какво да мигрирате към /var.
Полезни примери: pacman и NetworkManager
В Арч е удобно Преместете базата данни на Pacman в /usr/lib/pacman така че rootfs винаги да отразява инсталираните пакети. След това пренасочете кеша към /var/lib/pacman и го свържете. За да промените списъка с огледала, без да докосвате root-а, преместете го в /var/etc и го свържете въпреки това.
С NetworkManager, преместете системните връзки в /var/etc/NetworkManager и линк от /etc/NetworkManager/system-connections. Това запазва root-а непроменлив и конфигурацията остава активна там, където би трябвало да е достъпна за запис.
Конструиране на истинност и тестване
От живо копие и с всичко перфектно монтирано в ro, създайте дървото и roothash-а с формат на veritysetupПри изпълнение, той отпечатва реда Root Hash, който можете да запазите в roothash.txt. Стартирайте го за тестване с veritysetup, open root-device root verity-device $(cat roothash.txt) и mount /dev/mapper/root.
Ако предпочиташ, първо генерира дървото във файл (verity.bin) и след това го запишете в VERITY дяла. Полученият набор е: root image, verity tree и root hash, който ще запишете при зареждане.
Конфигурирайте линията на ядрото
Добавете тези параметри: 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=рестартиране y rd.shell=0 (предотвратяване на неоторизирани шелове, ако зареждането не успее) и карантина = поверителност за защита на паметта на ядрото от достъп.
Допълнителни прегради с verity
Не само коренът: Можете да дефинирате други съпоставяния в /etc/veritytab и systemd-veritysetup@.service ще ги асемблира при зареждане. Запомнете: по-лесно е да монтирате RW дял, различен от root, а root потребител може да деактивира Verity на тези дялове, така че стойността на сигурността там е по-ниска.
Сигурност: Secure Boot, UKI и подписани модули
dm-verity не е панацея. Подпишете UKI и активирайте Secure Boot със собствените си ключове за да се предотврати възможността някой да промени kernel/initramfs/cmdline (което включва root хеша). Инструменти като sbupdate-git или sbctl помагат за запазване на подписаните изображения и непокътнатостта на веригата за зареждане.
Ако активирате заключване на ядрото или проверка на подписа на модула, DKMS или модулите извън дървото трябва да бъдат подписани или няма да се заредят. Помислете за персонализирано ядро с поддръжка на подписване за вашия конвейер (вижте подписани модули на ядрото).
Криптиране, TPM и измерване
dm-verity защитава целостта, неповерителностМожете да оставите root некриптиран, ако не съдържа никакви секретни данни и веригата за зареждане е защитена. Ако използвате ключови файлове от root, за да отключите други томове, тогава е добра идея да го криптирате.
С 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 или неговият команден ред се променят.
Актуализации и модели на внедряване
Проверен root само за четене Не се актуализира с мениджъра на пакети по традиционния начинИдеалният вариант е да се създават нови изображения с инструменти като проектът Йокто и да ги публикувате. systemd има systemd-sysupdate и systemd-repart за стабилно изтегляне и флашване на образи.
Друга стратегия е А/Б схемаЗапазвате два корена и две verities. Копирайте активния корен в неактивния корен, приложете промените и повторете veritie. Включете отново при следващото зареждане. Ако използвате UKI, не забравяйте да актуализирате хеша на корена в cmd реда или да възстановите подписания UKI.
За опционална постоянство, използвайте OverlayFS върху проверения корен с upper в tmpfs или disk. Можете също да подадете systemd.volatile=overlay за временно запазване. Flatpak улеснява инсталирането на приложения в /var и /home, без да докосвате /.
Съществуват автоматизирани пакети (напр. verity-squash-root в AUR), които изграждат корен на squashfs и подпишете roothash-а с kernel и initramfs, което ви позволява да избирате между постоянен или ефимерен режим и запазване на най-новите rootfs файлове като резервно копие. Забележка: добавянето на постоянство към проверен root файл има ограничени случаи на употреба; опитайте да съхранявате данните на приложенията на отделни дялове.
Android: system-as-root, AVB и наслагвания на доставчици
От Android 10, RootFS спира да работи на RAM диска и се интегрира със system.img. (system-as-root). Устройствата, стартирани с Android 10, винаги използват тази схема и изискват ramdisk за dm-linear. BOARD_BUILD_SYSTEM_ROOT_IMAGE е зададено на false в тази компилация, за да се прави разлика между използването на ramdisk и директното активиране на system.img.
Включва Android 10 динамични дялове и инициализация от първи етап което активира логическия системен дял; ядрото вече не го монтира директно. Системните OTA изискват дизайн „система като root“, който е задължителен за устройства с Android 10.
В никакъв A/B случай, отделяйте възстановяването от зарежданетоЗа разлика от 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.
Типична имплементация: инсталира предварително компилираните файлове в устройството/ / /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 корупция, вашето устройство е ненадеждно. Команди като fastboot flash –disable-verity –disable-verification vbmeta vbmeta.img деактивират проверката, но оставят системата без никакви гаранции за целостта.
Някои буутлоудъри поддържат fastboot oem disable_dm_verity и неговата противоположност, enable_dm_verity. Работи на някои модели, но не и на други; и може да изисква kernel/magisk с коригирани флагове. Използвайте на свой собствен риск: разумният начин на действие е подравняване на boot, vbmeta и system, подпишете или регенерирайте дървото и се уверете, че очакваният хеш на корена съвпада с конфигурирания.
Ако след предупреждението можете да продължите да натискате бутона за захранване, системата ще стартира, но вече нямаш непокътната верига на довериеЗа да премахнете съобщението, без да жертвате сигурността, възстановете оригиналните подписани изображения или пресъздайте/проверете vbmeta с правилното хеш дърво, вместо да деактивирате verity.
i.MX и OpenWrt платформи
На i.MX6 (напр. sabresd), конфигурирайте ядрото с DM_VERITY и FEC поддръжка, генерирайте дървото с veritysetup, съхранете хеша на корена сигурно и предайте съответните параметри в cmd реда или интегрирайте чрез initramfs със systemd-veritysetup. Ако не използвате dm-crypt, не ви е необходим CAAM за verity; фокусът е върху целостта.
В OpenWrt и в вградени Linux системи с OpenEmbedded, Има усилия за интегриране на dm-verity и SELinux (Задачите на Bootlin са преработени с цел включване на поддръжка). Това е естествено съчетание: рутерите и мрежовото оборудване се възползват от непроменлив, проверен и MAC-засилен root.
Ръчно изграждане на дърво и метаданни (подробен изглед)
cryptsetup може да генерира дървото вместо вас, но ако предпочитате да разберете формата, дефиницията на компактния ред на таблицата включва: име на съпоставяне, устройство за данни, размери на блокове данни и хеш, размер на изображението в блокове, hash_start position (блоково изображение + 8, ако е конкатенирано), root hash и salt. След генериране на конкатенираните слоеве (отгоре надолу, с изключение на слой 0), записвате дървото на диск.
Да опаковам всичко, съставете таблицата dm-verity, подпишете я (типично RSA-2048) и групирайте таблицата с подписи в метаданните с версиран заглавен файл и магическо число. След това, той свързва системния образ, метаданните на verity и хеш дървото. В fstab, той маркира fs_mgr като verify и поставя публичния ключ в /boot/verity_key, за да валидира подписа.
Оптимизирайте с SHA-2 ускорения за вашия процесор и коригирайте read-ahead/prefetch_cluster. На ARM хардуер, NEON SHA-2 (ARMv7) и SHA-2 разширенията (ARMv8) значително намаляват разходите за проверка.
При всяко внедряване, не забравяйте, че Коренната хеш стойност трябва да бъде защитена: независимо дали е компилиран в подписан UKI, в подписания дял за зареждане или валидиран от зареждащата програма, използвайки AVB. Всичко след тази точка наследява това доверие.
С всичко горепосочено налице, dm-verity става солидна основа за непроменяеми, мобилни и вградени системи, поддържайки транзакционни актуализации, конфигурационни наслагвания и модерен модел за сигурност, който намалява повърхността за атака и предотвратява постоянството, без да се жертва производителността.


