
Si et preocupa la integritat del teu sistema, dm-verity és una de les peces clau de l'ecosistema Linux per arrencar amb garanties i detectar manipulacions a l'emmagatzematge. Va néixer com a part del device-mapper del nucli i avui és la base d'arrencada verificada en Android, OpenWrt i distribucions que busquen seguretat reforçada.
Lluny de ser un concepte abstracte, dm-verity es configura i utilitza amb eines reals com veritysetup i systemd-veritysetup, valida blocs al vol mitjançant arbres de hashes i pot reaccionar a corrupció amb polítiques que van des de registrar lesdeveniment fins a reiniciar o bloquejar el sistema. Ho veurem a fons i sense deixar serrells.
Què és dm-verity i per què t'interessa
dm-verity és un target de device-mapper al nucli que verifica la integritat d'un dispositiu de blocs a mesura que es llegeixen les dades. Funciona calculant i comprovant hashes de cada bloc (habitualment 4K) davant d'un arbre de verificació precomputat, normalment amb SHA-256.
Aquest disseny permet que els fitxers no es poden modificar silenciosament entre reinicis ni durant l'execució. És clau per estendre la cadena de confiança de l'arrencada cap al sistema operatiu, limitar persistència de codi maliciós, reforçar polítiques de seguretat i donar garanties a mecanismes de xifratge i MAC durant el boot.
A Android (des de la 4.4) i Linux en general, la confiança s'ancora al hash arrel de l'arbre, que està signat i validat amb una clau pública que resideix en una ubicació protegida (per exemple a la partició d'arrencada o en un UKI signat amb Secure Boot). Trencar qualsevol bloc requeriria fallir el hash criptogràfic subjacent.
La verificació es fa per bloc i sota demanda: la latència afegida és mínima comparada amb el cost d'E/S. Si una comprovació falla, el nucli torna un error d'E/S i el sistema de fitxers sembla danyat, que és el que s'espera quan les dades no són fiables. Les aplicacions poden decidir si continuen o no segons la seva tolerància a errors.
Com funciona internament l'arbre de verificació
L´arbre de verificació es construeix per capes. La capa 0 són les dades crues del dispositiu, dividides en blocs de 4K; de cada bloc es calcula un hash SHA-256 (amb sal). Aquests hashes es concatenen per formar la capa 1. Alhora, la capa 1 s'agrupa en blocs i es rehasea per formar la capa 2, i així successivament fins que cap tot en un únic bloc: aquest bloc, en hashearse, produeix el hash arrel.
Si alguna capa no completa exactament un bloc, s'omple amb zeros fins a assolir 4K per no deixar ambigüitats. La mida total de l'arbre depèn de la mida de la partició verificada; a la pràctica, sol quedar per sota d'uns 30 MB per a particions de sistema habituals.
El procés general és: tria una sal aleatòria, trosseja a 4K, calcula SHA-256 amb sal per bloc, concatena per formar nivells, emplena amb zeros a frontera de bloc i repeteix amb el nivell anterior fins a quedar-se amb un únic hash arrel. Aquest hash arrel, juntament amb la sal emprada, alimenta la taula de dm-verity i la signatura.
Versions de format en disc i algorisme
El format dels blocs de hash al disc té una versió. La versió 0 va ser l'original usada a Chromium OS: la sal s'afegeix al final en hashear, els digests s'emmagatzemen de forma contínua i la resta del bloc s'omple amb zeros.
La versió 1 és la recomanada per a dispositius nous: la sal s'anteposa en hashear i cada digest s'omple amb zeros fins a potències de dos, millorant alineament i robustesa. La taula dm-verity també especifica l'algorisme (per exemple, sha1 o sha256), encara que per a seguretat actual s'empra sha256.
Taula dm-verity i paràmetres essencials
La taula de destinació dm-verity descriu on són les dades, on és l'arbre de hashes i com verificar. Camps típics de la taula:
- dev: dispositiu amb les dades a verificar (ruta tipus /dev/sdXN o major: menor).
- hash_dev: dispositiu amb l'arbre de hashes (pot ser el mateix; si ho és, hash_start ha de quedar fora del rang verificat).
- data_block_size: mida de bloc de dades en bytes (p.ex. 4096).
- hash_block_size: mida de bloc de hash en bytes.
- num_data_blocks: nombre de blocs de dades verificables.
- hash_start_block: offset (en blocs de hash_block_size) fins al bloc arrel de l'arbre.
- algorithm: algoritme de hash (per exemple, sha256).
- digestor: codificació hexadecimal de l'hash del bloc arrel (incloent sal segons versió de format); aquest valor és el que cal confiar.
- sal: sal en hexadecimal.
A més, hi paràmetres opcionals molt útils per ajustar el comportament:
- ignore_corruption: registra blocs corruptes, però permet continuar llegint.
- restart_on_corruption: reinicieu en detectar corrupció (no compatible amb ignore_corruption i requereix suport en espai d'usuari per evitar bucles).
- panic_on_corruption: fa panic en detectar corrupció (no compatible amb les anteriors).
- restart_on_error y panic_on_error: mateixes reaccions però per a errors d'E/S.
- ignore_zero_blocks: no verifica blocs que s'esperen com a zeros i retorna zeros.
- use_fec_from_device + fec_roots + fec_blocks + fec_start: habilita FEC (Reed-Solomon) per recuperar dades quan falli la verificació; les àrees de dades, hash i FEC no s'han de solapar i les mides de bloc han de coincidir.
- check_at_most_once: verifica cada bloc de dades només la primera vegada que es llegeix (redueix overhead a costa de seguretat en atacs en viu).
- root_hash_sig_key_desc: referència a una clau al keyring per validar una signatura PKCS7 del hash arrel en la creació del mapeig (requereix la configuració de kernel adequada i keyrings de confiança).
- try_verify_in_tasklet: si els hashes estan en memòria cau i la mida d'E/S ho permet, verifica en bottom-half per reduir latència; s'ajusta amb /sys/module/dm_verity/parameters/use_bh_bytes per classe d'E/S.
Signatura, metadades i ancoratge de confiança
Perquè dm-verity sigui fiable, l'arrel hash ha de confiar-se i, normalment, signar-se. A Android clàssic s'inclou una clau pública a la partició d'inici que el fabricant verifica externament; amb ella es valida la signatura del hash arrel i es garanteix que la partició de sistema no ha estat alterada.
Les metadades de verity afegeixen estructura i control de versions. El bloc de metadades inclou un número màgic 0xb001b001 (bytes b0 01 b0 01), versió (actualment 0), la signatura de la taula a PKCS1.5 (típicament 256 bytes per a RSA-2048), la longitud de la taula, la taula mateixa i farcit amb zeros fins a 32K.
En implementacions Android, la verificació es recolza en fs_mgr i fstab: afegint la marca de verificació a l'entrada corresponent i col·locant la clau a /boot/verity_key. Si el número màgic no apareix on toca, la verificació s'atura per evitar verificar allò que no correspon.
Operació de l'arrencada verificada
La protecció viu al nucli: si es compromet abans que el nucli arrenqui, l'atacant reté el control. Per això els fabricants solen validar fermament cada etapa: una clau cremada al dispositiu verifica el primer bootloader, que verifica el següent, el bootloader d'apps i, finalment, el kernel.
Amb el nucli verificat, dm-verity s'activa en muntar el dispositiu de blocs verificat. En comptes d'haixejar tot el dispositiu (que seria lent i gastaria energia), es verifica bloc a bloc quan s'hi accedeix. Una fallada provoca error d'E/S, i serveis i apps reaccionen segons la tolerància: seguir sense aquestes dades o fallar amb contundència.
Correcció d'errades per endavant (FEC)
Des d'Android 7.0, s'hi incorpora FEC (Reed–Solomon) amb tècniques d'entrellaçat per reduir espai i augmentar la capacitat de recuperar blocs danyats. Això conviu amb dm-verity: si una verificació falla, el subsistema pot intentar correcció abans de declarar-ho irrecuperable.
Rendiment i optimització
Per reduir impacte: activa acceleració de SHA-2 per NEON a ARMv7 i extensions SHA-2 a ARMv8 des del nucli. Ajusta paràmetres de read-ahead i prefetch_cluster per al maquinari; la verificació per bloc sol afegir poc davant el cost d'E/S, però aquests paràmetres marquen diferències.
Posada en marxa a Linux (systemd, veritysetup) i Android
En un Linux modern amb systemd, dm-verity permet un root de només lectura verificat usant veritysetup (part de cryptsetup), systemd-veritysetup.generator i systemd-veritysetup@.service. És recomanable acompanyar-lo de Secure Boot i un UKI (unified kernel image) signat, encara que no són estrictament obligatoris.
Preparació i particionament recomanat
Parteix d'un sistema funcional i ajustat. Reserva un volum per a l'arbre de hashes (8–10% de la mida de l'arrel sol ser suficient) i valora separar /home i /var si necessites escriptura. Un esquema típic inclou: ESP (per al bootloader), XBOOTLDR (per a UKIs), arrel (amb xifrat o sense), partició VERITY, i opcionalment /home i /var.
Com a arrel, EROFS és una alternativa molt interessant a ext4 o squashfs: és de només lectura per disseny, amb rendiment molt bo en flash/SSD, compressió lz4 per defecte i àmpliament usat en mòbils Android amb dm-verity.
Fitxers que han de ser escrivibles
Amb arrel, alguns programes esperen escriure a /etc o durant l'init. Podeu moure a /var/etc i enllaçar simbòlicament el que heu de canviar (p.ex. connexions de NetworkManager a /etc/NetworkManager/system-connections). Tingues en compte que systemd-journald exigeix que /etc/machine-id existeixi a l'arrel (no un symlink) per no trencar arrencades primerenques.
Per descobrir què canvia en execució, utilitza dracut-overlayroot: superposa un tmpfs sobre l'arrel, i tot allò escrit apareix a /run/overlayroot/u. Afegeix el mòdul a /usr/lib/dracut/modules.d/, inclou overlayroot a dracut i posa overlayroot=1 a la línia de kernel; així veuràs què migrar a /var.
Exemples útils: pacman i NetworkManager
A Arch, convé moure la base de dades de pacman a /usr/lib/pacman perquè el rootfs reflecteixi sempre els paquets instal·lats. Després, redirigeix la memòria cau a /var/lib/pacman i enllaça. Per canviar mirrorlist sense tocar l'arrel, mou-la a /var/etc i enllaça igual.
Amb NetworkManager, trasllada system-connections a /var/etc/NetworkManager i enllaça des de /etc/NetworkManager/system-connections. Així mantenes arrel immutable i configuració viva on ha de ser escrivible.
Construcció del verity i prova
Des d'un live i amb tot perfecte i muntat amb ro, crea l'arbre i roothash amb veritysetup format: en executar-se, imprimeix la línia del Root Hash que pots desar a roothash.txt. Obre per a prova amb veritysetup open root-device root verity-device $(cat roothash.txt) i munta /dev/mapper/root.
Si prefereixes, genera primer l'arbre a un fitxer (verity.bin) i després escriu-lo a la partició VERITY. El conjunt resultant són: imatge arrel, arbre verity i el roothash que ancoraràs a l'arrencada.
Configurar la línia del nucli
Afegeix aquests paràmetres: systemd.verity=1, roothash=contingut_de_roothash.txt, systemd.verity_root_data=RUTA-RAIZ (per exemple LABEL=OS) i systemd.verity_root_hash=RUTA-VERITY (per exemple LABEL=VERITY). Ajusteu systemd.verity_root_options a restart-on-corruption o panic-on-corruption per a polítiques estrictes.
Altres opcions recomanables: ro (si no uses EROFS/squashfs), rd.emergency=reboot y rd.shell=0 (evitar shells no autoritzades si falla l'arrencada), i lockdown=confidenciality per protegir memòria del nucli davant d'accessos.
Particions addicionals amb verity
No només l'arrel: pots definir altres mapeigs a /etc/veritytab i systemd-veritysetup@.service els assemblarà al boot. Recorda: és més fàcil remuntar a rw una partició no root i un usuari amb root podria desactivar verity en aquestes particions, així que el valor de seguretat aquí és menor.
Seguretat: Secure Boot, UKI i mòduls signats
dm-verity no és bala de plata. Signa l'UKI i habilita Secure Boot amb claus pròpies per evitar que algú substitueixi kernel/initramfs/cmdline (que inclou el roothash). Eines com sbupdate-git o sbctl ajuden a mantenir imatges signades i la cadena d'arrencada íntegra.
Si actives kernel lockdown o verificació de signatures de mòduls, els mòduls DKMS o out-of-tree han de signar-se o no carregaran. Valora un kernel personalitzat amb suport de signatura per al teu flux (vegeu mòduls de kernel signats).
Xifratge, TPM i mesurament
dm-verity protegeix integritat, no confidencialitat. Podeu deixar l'arrel sense xifrar si no conté secrets i la cadena d'arrencada està protegida. Si utilitzeu keyfiles des de l'arrel per desbloquejar altres volums, llavors sí que convé xifrar-la.
Amb TPM 2.0, systemd-cryptenroll permet enllaçar claus a PCRs 0,1,5,7 (firmware, opcions, GPT, estat de secure boot). Afegeix rd.luks.options=UUID_de_LUKS=tpm2-device=auto i assegureu-vos d'incloure suport TPM2 a l'initramfs. systemd-boot mesura el kernel.efi a PCR4, útil per invalidar claus si canvia l'UKI o el seu cmdline.
Actualitzacions i models de desplegament
Un root de només lectura verificat no s'actualitza amb el gestor de paquets tradicionalment. L'ideal és construir imatges noves amb eines com el projecte Yocto i publicar-les. systemd té systemd-sysupdate i systemd-repart per baixar i flaixar imatges de forma robusta.
Una altra estratègia és esquema A/B: mantens dues arrels i dues verity. Copieu l'activa a la inactiva, apliqueu canvis i refeu verity. A la següent arrencada commutes. Si utilitzeu UKI, recordeu actualitzar el roothash a la cmdline o reconstruir l'UKI signat.
Per a persistència opcional, utilitza OverlayFS sobre l'arrel verificada amb upper a tmpfs o disc. També podeu passar systemd.volatile=overlay per a persistència temporal. Flatpak facilita instal·lar apps a /var i /home sense tocar /.
Hi ha paquets que automatitzen (p.ex. verity-squash-root a AUR) que construeixen un root squashfs i signen el roothash amb kernel i initramfs, permetent triar entre mode persistent o efímer i conservar l'últim rootfs com a backup. Ull: afegir persistència a una arrel verificada té casos d'ús estrets; intenta persistir dades d'apps a les particions separades.
Android: system-as-root, AVB i overlays de vendor
Des d'Android 10, el rootfs deixa d'anar a ramdisk i s'integra amb system.img (system-as-root). Dispositius que llancen amb Android 10 usen sempre aquest esquema i necessiten ramdisk per dm-linear. BOARD_BUILD_SYSTEM_ROOT_IMAGE es configura en false en aquesta generació per distingir ús de ramdisk davant activar system.img directament.
Android 10 incorpora particions dinàmiques i un init de primera etapa que activa la partició de sistema lògica; el nucli ja no la munta directament. Les OTA sols-sistema requereixen un disseny system-as-root, obligatori en dispositius amb Android 10.
En no A/B, mantingues recovery separat de boot. A diferència d'A/B, no hi ha suport boot_a/boot_b, així que eliminar recovery en no A/B pot deixar-te sense mode recuperació si falla una actualització de boot.
El nucli munta system.img a / amb verity mitjançant dues vies: vboot 1.0 (pegats perquè el kernel analitzi metadades Android a /system i derivi paràmetres dm-verity; la cmdline inclou root=/dev/dm-0, skip_initramfs i init=/init amb dm=…) o vboot 2.0/AVB, on el bootloader integra libavb, llegeix el descriptor hashtree (en vbmeta o system), construeix els paràmetres i els passa al kernel a la cmdline, amb suport de FEC i indicadors com a restart_on_corruption.
Amb system-as-root, no utilitzis BOARD_ROOT_EXTRA_FOLDERS per a carpetes arrel específiques del dispositiu: desapareixeran en flashejar una GSI. Defineix muntatges específics sota /mnt/vendor/ , que fs_mgr crea automàticament, i referiu-los al fstab de l'arbre de dispositiu.
Android permet una superposició de vendor des de /product/vendor_overlay/: init muntarà a /vendor els subdirectoris que compleixin requisits de context SELinux i existència de /vendor/ . Requereix CONFIG_OVERLAY_FS=yy, en nuclis antics, el pegat d'override_creds=off.
Implementació típica: instal·la fitxers precompilats a device/ / /vendor_overlay/, afegeix-los a PRODUCT_COPY_FILES amb find-copy-subdir-files cap a $(TARGET_COPY_OUT_PRODUCT)/vendor_overlay, defineix contextos en file_contexts per a etc i app (per exemple vendor_configs_file i vendor_app_file) i permet en initte. Prova amb atest vfs_mgr_vendor_overlay_test a userdebug.
Solució de problemes: missatge de dm-verity corruption a Android
En dispositius amb slots A/B, canviar de slot o flashear vbmeta/boot sense coherència amb el roothash pot disparar l'avís: dm-verity corruption, el vostre dispositiu no és de confiança. Comandes com fastboot flash –disable-verity –disable-verification vbmeta vbmeta.img desactiven verificació, però deixen el sistema sense garanties d'integritat.
Alguns bootloaders admeten fastboot oem disable_dm_verity i el seu oposat enable_dm_verity. En certs models funciona, en altres no; i pot requerir kernel/magisk amb flags ajustades. Fes-lo servir sota la teva responsabilitat: el prudent és alinear boot, vbmeta i system, signar o regenerar l'arbre i assegurar-vos que el hash arrel esperat coincideix amb el configurat.
Si després de l'avís pots continuar fent clic encès, el sistema arrenca, però ja no tens cadena de confiança intacta. Per eliminar el missatge sense sacrificar seguretat, restableix imatges originals signades o reconstrueix/verifica vbmeta amb el hashtree correcte, en comptes de desactivar verity.
Plataformes i.MX i OpenWrt
A i.MX6 (per exemple sabresd), configura el kernel amb DM_VERITY i suport FEC, genera l'arbre amb veritysetup, guarda el roothash de forma fiable i passa els paràmetres adequats a la cmdline o integra via initramfs amb systemd-veritysetup. Si no utilitzeu dm-crypt, no necessiteu CAAM per a verity; el focus està en integritat.
A OpenWrt ia sistemes Linux embegut amb OpenEmbedded, hi ha esforços per integrar dm-verity i SELinux (treballs de Bootlin revisats amb la intenció d'incorporar suport). És un encaix natural: encaminadors i equips de xarxa es beneficien d'arrel immutable, verificada i endurida amb MAC.
Construcció manual de l'arbre i metadades (visió detallada)
cryptsetup et pot generar l'arbre, però si prefereixes entendre el format, la definició compacta de la línia de taula inclou: nom del mapeig, dispositiu de dades, mides de bloc de dades i hash, mida d'imatge en blocs, posició del hash_start (imatge en blocs + 8 si concatenes), root hash i sal. Després de generar les capes concatenades (de dalt a baix, excloent-ne la capa 0), escrius l'arbre en disc.
Per empaquetar-ho tot, compon la taula dm-verity, signa-la (RSA-2048 típica) i agrupa signatura+taula en metadades amb capçalera versionada i número màgic. Després, concatena imatge de sistema, metadades verity i arbre de hash. A fstab, marca fs_mgr amb verify i col·loca la clau pública a /boot/verity_key per validar la signatura.
Optimitza amb acceleracions SHA-2 de la teva CPU i ajusta read-ahead/prefetch_cluster. Al maquinari ARM, NEON SHA-2 (ARMv7) i extensions SHA-2 (ARMv8) redueixen significativament la càrrega de verificació.
En qualsevol desplegament, recorda que el valor de l'arrel hash ha d'estar protegit: ja sigui compilat en un UKI signat, a la partició de boot signada o validat pel bootloader amb AVB. Tot el que passi després d'aquest punt hereta aquesta confiança.
Amb tot això al seu lloc, dm-verity es converteix en un fonament sòlid per a sistemes immutables, mòbils i embeguts, compatible amb actualitzacions transaccionals, overlays de configuració i un model de seguretat modern que redueix la superfície datac i evita persistència sense sacrificar rendiment.


