dm-verity是什麼?它如何保護系統完整性?

最後更新: 08/01/2026
作者: 艾薩克
  • dm-verity 使用加密雜湊樹即時驗證資料區塊,防止對關鍵分割區進行靜默變更。
  • 信任建立在根哈希及其簽名之上,並整合到一條鏈中。 開機 已與引導程式、核心和安全啟動進行驗證。
  • Android, Linux 嵌入式系統使用 dm-verity 作為唯讀根,並將其與 FEC 結合使用。 TPM的 並採用加密技術來加強系統安全。
  • 使用 dm-verity 更新系統基於不可變鏡像、A/B 方案和覆蓋層,避免直接變更已驗證的根目錄。

Linux 6.18 的新特性

如果你從事 Android、Linux 或嵌入式系統的工作,你可能看過類似「dm-verity 損壞」的錯誤訊息,或聽過驗證啟動 (Verified Boot)、AVB 或安全啟動 (Secure Boot)。而這一切的背後,都離不開核心的關鍵部分: dm-verity 是一種旨在確保檔案系統未被篡改的機制。設備開機時或重新啟動後均無法進行此操作。

這看似是個小問題,但實際上會影響日常生活,例如手機無法保持連線。 惡意軟件 隱藏在系統分區中,或者說, 路由器 或者說,「封閉式」伺服器總是以相同的可靠狀態啟動。 dm-verity 依靠 SHA-256 哈希樹和加密簽章逐區塊驗證磁碟上的資料是否仍然符合預期。如果發生異常情況,核心可以返回讀取錯誤、重新啟動計算機,甚至崩潰以避免繼續執行可疑程式碼。

dm-verity是什麼?它解決了什麼問題?

dm-verity 是 Linux 核心裝置映射子系統的一個目標,它允許對區塊裝置的完整性進行即時驗證。這通常是一個包含根檔案系統或關鍵分區(例如 Android 上的 /system)的分區或鏡像。與「盲目」讀取磁碟不同,每次存取的資料區塊都會根據預先計算的雜湊樹進行加密校驗。

UEFI系統中啟動過程的描述
相關文章:
UEFI系統啟動過程的詳細描述

自 Android 4.4 版本起以及許多現代 Linux 發行版上, dm-verity 是已驗證啟動的基礎這樣可以確保系統分割區與建立鏡像時完全相同。這使得rootkit或其他類型的惡意軟體難以在重新啟動後透過向系統中註入惡意檔案或二進位檔案而持續存在。

這種方法的優點之一是: dm-verity 裝置在 /dev/mapper 下顯示為普通區塊裝置。這樣一來,它們就可以像普通磁碟一樣掛載。對於上述檔案系統(ext4、EROFS、squashfs 等),一切似乎都很標準,但每次讀取操作都會經過 verity 加密過濾器。

必要性:惡意軟體擁有 root 權限和受信任啟動權限

所有類型的惡意軟體-6

在像安卓這樣的系統中, 取得權限的應用程式或二進位文件 它們比探測系統本身更善於隱藏。由於擁有比防毒軟體或安全工具更多的權限,它們可以「謊報」檔案、進程或配置,使它們更難被檢測和刪除。

如果沒有像 dm-verity 這樣的機制, 攻擊者可以修改系統二進位檔案、庫檔案或啟動腳本來實現持久化。從而阻止允許使用的工具 驗證文件完整性 它們會偵測到這種篡改;也就是說,即使你重新啟動設備,它們仍然存在。這就是持久性rootkit的典型惡夢。

dm-verity 在系統底層扮演守護者的角色: 核心只接受符合校驗樹預期雜湊值的區塊作為有效資料區塊。如果有人手動更改了系統分區,則雜湊值將不再匹配,核心在嘗試讀取已更改的資料時會立即檢測到這一點。

dm-verity 的內部運作原理

基本理念很簡單,但卻很強大: 在裝置的所有資料區塊上建立一個加密哈希樹(通常為 SHA-256)。按層級結構。該樹儲存在磁碟上,在正常使用過程中,用於驗證每個資料區塊的讀取。

哈希樹結構

驗證樹由多個層級構成。 第 0 層包含實際資料(例如,系統的 ext4/EROFS 鏡像),分為 4K 區塊。對於每個資料區塊,都會計算一個 SHA-256 雜湊值(通常會使用隨機鹽來加強預計算攻擊)。

將第 0 層中的雜湊值連接起來形成第 1 層。 第一層資料被重新分組為 4K 區塊,並對每個產生的區塊計算 SHA-256 雜湊值。產生第 2 層。這個過程逐層重複,直到所有雜湊值都適合放入一個區塊中;最後一個區塊的雜湊值就是根雜湊值,它代表了整棵樹。

當圖層無法填滿整個區塊時, 它前面全是零,直到達到 4K。這樣可以避免歧義,並能檢測到試圖透過用任意資料取代部分來「切割」樹的行為:預期的結構包括已知的零填充。

光碟上, 樹狀結構是透過從頂層向下逐層連接(不包括資料層 0)來儲存的。樹的總大小取決於所檢查分割區的大小,但實際上它通常很小,即使對於大型系統分割區,通常也小於 30 MB。

格式版本和哈希演算法

哈希塊的儲存格式一直在不斷演變。 該格式的第 0 版最初由 Chromium OS 使用,在計算雜湊值時在末尾添加了鹽值,並連續儲存摘要。將剩餘部分填入零。

  我的 Android 鍵盤無法使用。

版本 1,推薦用於新系統, 計算哈希值時,將鹽值放在資料之前。 並將每個摘要填入 2 的冪次方。這提高了對齊度,並增強了對某些類型攻擊或篡改的穩健性。 dm-verity 表也指示了所使用的演算法(sha1、sha256 等),儘管現在使用 SHA-256 更為合理。

逐步計算根哈希值

如果你想親手建造這棵樹,整體思路是清晰的。 首先,以十六進位格式選擇一個隨機鹽值,將影像分成 4K 個區塊,然後計算每個區塊的加鹽 SHA-256 值。這些哈希值構成了資料之上的第一個「邏輯」層。

那麼, 哈希值會被連接起來,直到填滿 4K 個區塊。如果空間不足,則用零填滿。每個產生的區塊也使用 SHA-256 演算法進行哈希運算,以形成樹的下一層。這種「哈希哈希」的過程不斷重複,直到最終得到一個哈希值:即根哈希值。

在實際應用中,像 cryptsetup/veritysetup 這樣的工具會處理所有這些計算並直接生成 樹檔案(verity.bin)和根哈希值(roothash),可用於 dm-verity 表或簽章元資料中。

dm-verity 表:描述驗證的內容和方法

為了使內核能夠使用 dm-verity,它需要準確描述資料的位置、哈希樹的位置以及要使用的參數。 該描述是 dm-verity 表,它是裝置映射器在建立已驗證的邏輯裝置時解釋的一系列參數。.

在一個 典型的簡化版該定義可以理解為:

最重要的領域 dm-verity 表通常包含:

  • 開發:包含要驗證的資料的裝置(例如,/dev/sdXN 分割區或主裝置號:次裝置號對)。
  • hash_dev:儲存哈希樹的裝置;它可以與 dev 相同,只要 hash_start 指向已驗證資料範圍之外即可。
  • 資料塊大小:資料塊大小(以位元組為單位),通常為 4096。
  • hash_block_size哈希塊大小通常也為 4096。
  • 資料區塊數量要保護的資料塊數量。
  • hash_start_block:從設備起始位置到哈希樹起始位置的偏移量(以區塊為單位)。
  • 算法哈希演算法(sha256 是事實上的標準)。
  • 摘要(根哈希):樹的根塊的哈希值,以十六進位表示;它是可信的「錨點」。
  • :計算哈希值時使用的鹽值,也以十六進位表示。

除了這些基本領域之外, 有一些可選參數可以調整系統對資料損壞或錯誤的反應方式。例如,您可以指定,如果發生資料損壞,系統應該重新啟動、觸發恐慌,或忽略該問題,只記錄到系統中。 日誌或者說,FEC恢復在故障發生前就已經被啟動。

進階表格選項:腐敗度、FEC 和效能

dm-verity 包含一組用於分析行為的標誌。 ignore_corruption 允許即使偵測到資料損壞也繼續讀取,但會在日誌中留下痕跡。適用於以可用性優先於嚴格完整性的環境。

如果你想要的是強而有力的管教, `restart_on_corruption` 或 `panic_on_corruption` 在程式碼區塊驗證失敗時強制重啟或引發 panic。類似的變體也適用於 I/O 錯誤(restart_on_error、panic_on_error)。此外,還有一個 ignore_zero_blocks 選項,它會避免檢查預期為零的資料區塊,並直接傳回零。

對於整合前向校正的系統, `use_fec_from_device` 與 `fec_roots`、`fec_blocks` 和 `fec_start` 一起啟用了 Reed-Solomon 程式碼的使用。使用 FEC,如果驗證失敗,可以在認為資料區塊遺失之前,嘗試使用冗餘資訊重建資料區塊。

其他選項,例如 check_at_most_once, 它們允許每個資料塊僅在首次存取時進行驗證。這降低了開銷,但代價是無法偵測到即時修改;這是安全性和效能之間的權衡。諸如 `root_hash_sig_key_desc` 之類的標誌允許核心使用儲存在金鑰環中的金鑰來驗證根雜湊的 PKCS7 簽章。

簽章、元資料和驗證魔數

要使一切有意義,根哈希值必須可靠。 在經典的安卓系統中,公鑰包含在啟動分區中,製造商負責在外部進行驗證。此金鑰用於驗證根哈希或 dm-verity 表的簽名,以確保哈希樹未被竄改。

Verity 的元資料封裝了這些資訊。 一個 32K 的資料區塊包含一個魔數、版本號碼、簽名、表格長度和內容,以及用零填滿的部分。這種受控結構使得元資料能夠被準確定位和驗證,而不會產生歧義。

典型場 此元資料包括:

  • 神奇數字: 固定值為 0xb001b001,供 fs_mgr 等元件辨識為有效的驗證區塊。
  • :目前為 0,用於將來引入格式變更。
  • 公司:dm-verity 表簽名,通常為 PKCS1.5,金鑰為 RSA-2048(256 位元組)。
  • 表格長度:儲存在下面的 dm-verity 表的大小(以位元組為單位)。
  • 塔不拉:序列化的 dm-verity 表本身。
  • 釀的:直到 32.000 位元組的資料塊完成之前,其餘部分均為零。
  Ios的變化這麼慢嗎?

如果在分析系統映像結束時未找到魔數, 假設分區尚未準備好進行驗證,且驗證過程尚未啟動。例如,這可以防止將未驗證的分割區視為已驗證分割區。

在Android上, fs_mgr 和 fstab 檔案控制要檢查哪些分割區。只需新增勾選標記(例如,在 fs_mgr 標誌中新增「驗證」),並將對應的公鑰放在 /boot/verity_key 中,即可啟動端對端驗證流程。

它與已驗證的新創公司有何關聯?

如果攻擊者可以偷偷植入一個修改過的核心或引導程序,從而接受任何內容,那麼 dm-verity 就沒什麼用處了。 因此,在 移動 以及安全平台,根哈希和 dm-verity 表是信任鏈的一部分,該信任鏈始於 硬件.

通常情況下,製造商會將公鑰燒錄到裝置上。 此金鑰驗證第一個引導程式的簽名,而該程式又會檢查下一層,即第二個引導程式。 應用程序 最後,是內核影像。從那裡開始,經過驗證的核心接管控制權,並使用 dm-verity 將這種信任擴展到系統分區。

在採用 AVB(Android Verified Boot 2.0)的現代 Android 系統上, 引導程式整合了 libavb,並讀取分區或 vbmeta 中的哈希樹描述符。利用這些訊息,它建立 dm-verity 參數,並將其傳遞給核心。 命令以及諸如是否有聯邦選舉委員會、發生腐敗時該如何處理等說明。

Android 上的 dm-verity:系統以 root 使用者身分執行、AVB 和損壞訊息

多年來,Android 一直依賴 dm-verity。 自 Android 4.4 起,它被用作驗證啟動的基礎,而從 Android 10 開始,系統即 root 的設計直接將 rootfs 整合到 system.img 中。消除了許多經典設置,並強制從第一階段初始化開始處理 dm-verity。

借助系統即根目錄和現代OTA更新, 系統分區通常是唯讀的,並由經過驗證的哈希樹保護。核心透過 dm-verity 裝置來識別它,這對 Android 頂層是透明的。

插槽 A/B、vbmeta 和「dm-verity 損壞」錯誤

在採用 A/B 方案的設備中,很容易出現錯置的情況。 如果在刷入 boot 或 vbmeta 時,它們與 roothash 和實際系統分割樹不匹配,則通常會出現可怕的訊息「dm-verity 損壞,您的裝置不受信任」。.

要繞過驗證,可以使用類似這樣的指令: fastboot flash –disable-verity –disable-verification vbmeta vbmeta.img或者,在某些廠商的廠商中,可以使用 `fastboot oem disable_dm_verity` 指令。但請注意: 這將停用驗證啟動並消除完整性保證。即使你成功啟動了它,而且沒有出現煩人的消息。

最「乾淨俐落」的解決方法包括 請確保系統鏡像、啟動鏡像和 vbmeta 鏡像彼此一致。重新產生(或恢復)驗證樹,並更新簽章或描述符,使預期的根雜湊值與實際的根雜湊值相符。只有這樣才能在不影響信任鏈完整性的情況下維護信任鏈。 技巧 佩利格羅索斯。

與 TWRP、已解鎖的引導程式和模組的關係

在現實世界中,許多人在安裝 ROM、修改核心或進行 root 操作時都會遇到 dm-verity。 要使用 TWRP、刷寫韌體或安裝模組,通常需要解鎖引導程式。因為經過驗證的啟動過程會阻止啟動未經製造商簽署的映像。

有些程序建議,例如: 首先,刷入特定的固件,重啟進入引導程序,然後執行諸如“fastboot oem disable_dm_verity”之類的命令,接著執行“fastboot oem enable_dm_verity”之類的命令。然後安裝較新的韌體。這些步驟旨在「重置」Verity狀態,以便接受新鏡像而不會出現損壞提示。

如果在崩潰或刷機錯誤後,每次重新啟動時都會出現「dm-verity corrupt」警告, 最好檢查一下分區系統是否有物理損壞,以及你使用的圖片是否與你的型號相符。有時,數據機、啟動韌體和系統韌體之間的簡單不匹配就可能導致已驗證的啟動過程出現問題。

Linux 桌面和伺服器上的 dm-verity(systemd、veritysetup)

dm-verity 並非 Android 獨有。 在現代 Linux 發行版中,尤其是在 systemd 系統中,它正逐漸成為高信任度、唯讀 root 系統的基礎。這與某些路由器、家用電器或媒體盒的工作原理非常相似。

使用 dm-verity 的典型根掛載包括: 根鏡像或分區、包含 verity 樹的檔案 (verity.bin)、根雜湊值、systemd-veritysetup 單元以及對應的核心行參數(可選)添加已簽署的 UKI(統一核心映像)和安全啟動,以使整個系統得到充分保護。

分區方案和檔案系統

通常的建議是為哈希值預留一個專門的分區。 常用的配置包括:一個 EFI 分區 (ESP)、一個用於 UKI 的 XBOOTLDR 分區、一個根分區(帶或不帶加密)、一個用於目錄樹的 VERITY 分區,以及可選的可寫入 /home 和 /var 分區。.

根檔案系統不是傳統的 ext4, EROFS 是一個非常有趣的選擇它採用唯讀設計,具有非常好的閃存性能,並且 SSD 它開箱即用,支援LZ4壓縮。它與dm-verity一起廣泛應用於安卓手機上,這絕非偶然。

需要編寫的文件和常用技巧

如果根目錄以唯讀方式掛載,則需要仔細考慮哪些檔案需要可修改。 許多程式都希望寫入 /etc、/var 或類似路徑。與其將 /etc 完全設為可寫,不如只將必要的內容移到 /var/etc,然後從 /etc 以符號連結的方式將其連結起來,這樣效率更高。

  如何去除 iPhone 螢幕保護貼上的氣泡?

例如: NetworkManager 連線可以移到 /var/etc/NetworkManager/system-connections 目錄。 並保留一個指向 /etc/NetworkManager/system-connections 的符號連結。這樣既不會破壞不可變的根目錄設計,又能方便地修改需要更改的配置。

為了發現啟動和執行過程中實際寫入的內容, 您可以使用 dracut-overlayroot,它會在根目錄上掛載一個 tmpfs 覆蓋層,並將所有實際寫入操作記錄在 /run/overlayroot/u 中。使用系統一段時間後,只需檢查目錄,即可找出需要從已驗證的根目錄中移除的內容。

這在 Arch Linux 中也很常見 將 pacman 資料庫遷移到 /usr/lib/pacman,快取遷移到 /var/lib/pacman這樣,根映像始終反映系統的「密封」狀態,而同步和更新操作在可寫入區域中執行。

使用 systemd 建立驗證並配置啟動過程

典型流程 在想要使用 dm-verity 進行 root 存取的 Linux 系統中,應該這樣寫:

  • 從運行環境啟動,並將根目錄掛載為唯讀。一旦系統完全按照您的意願設定好,它就會被「凍結」。
  • 運行 `veritysetup format root-device verity-device` 以產生哈希樹和根哈希。該命令通常會列印出包含根哈希的行,該哈希保存在一個檔案中(例如 roothash.txt)。
  • 使用 veritysetup open 測試映射建立並掛載經過驗證的 /dev/mapper/root,以檢查一切是否正常運作。

接下來,您需要調整內核命令列。 使用 systemd 時,會使用 systemd.verity=1、roothash=…、systemd.verity_root_data=… 和 systemd.verity_root_hash=… 等參數。此外,也可以根據所需的安全性選擇 systemd.verity_root_options=restart-on-corruption 或 panic-on-corruption 等選項。

如果使用 UKI, 所有這些參數都整合到 kernel.efi 鏡像中,該鏡像已簽署並使用安全啟動功能啟動。這樣可以防止有人在命令列上更改根哈希值而不使簽名失效,從而維護信任模型。

安全啟動、加密和TPM:如何將它們完美結合

dm-verity 只保證完整性,不保證保密性。 如果資料未加密,則可以查看,但無法在不被發現的情況下進行更改。因此,它通常與加密(LUKS)和TPM結合使用,以保護金鑰。

一種常用的策略是 使用 systemd-cryptenroll 將 LUKS 解密金鑰錨定到某些 TPM PCR。 (例如 PCR 0、1、5、7),因此變更韌體、分區佈局或安全啟動狀態會使金鑰失效。這可以防止攻擊者停用安全啟動,從而偷偷植入一個忽略驗證機制的內核,同時又不破壞解密鏈。

如果使用 systemd-boot, 引導程式在 PCR 4 中測量 kernel.efi 映像。如果該措施發生變化,則不會釋放相關金鑰,也不會開啟加密分割區。這是確保核心、initramfs 和命令列(包括 roothash)未被竄改的另一環節。

根目錄以外的用途:其他分區、覆蓋層和更新

雖然保護根係是最常見的做法, dm-verity 可以應用於啟動時掛載的其他分割區。在具有 systemd 的系統中,這些額外的分區在 /etc/veritytab 中描述,並由 systemd-veritysetup@.service 自動配置。

然而,經過驗證的非根分區安全性較低: 它可以相對容易地進行讀寫恢復,root 使用者甚至可以停用其上的 Verity 功能。即便如此,它對於你想監控的資料或掛載在其他位置的唯讀影像仍然很有用。

關於更新,已驗證的唯讀根目錄會改變人們的思考模式。 管理員不應該在生產根目錄上執行“pacman -Syu”或類似命令。而是產生系統的新映像及其對應的真實樹,並以事務方式部署。

針對這種情況,有幾種策略可供選擇: 使用 systemd-sysupdate 和 systemd-repart 等工具下載並刷寫新鏡像或者提出一個具有兩個根和兩個真理的 A/B 方案,其中更新不活躍的分區,然後交換角色。

如果你想要更靈活的方案, 經過驗證的根目錄可以掛載為 OverlayFS 上的一個較低層目錄,而上層目錄則可以掛載為 tmpfs 或磁碟。因此,變更應用於頂層,但底層鏡像仍然是經過驗證的鏡像。您甚至可以選擇可選或臨時持久性(例如,systemd.volatile=overlay)來實現「一次性會話」。

在桌面領域,諸如以下技術 Flatpak 非常符合這種理念。它們在 /var 和 /home 目錄下安裝和更新應用程序,而無需觸及受 verity 保護的根目錄。這維護了一個不可變的基礎系統,並允許獨立管理應用程式。

整個生態系統使得 dm-verity 不僅僅是一個核心新奇事物: 它是不可更改、移動和嵌入式系統的基石,這些系統始終需要從已知狀態啟動,並能偵測任何篡改行為。 存儲它與驗證啟動、安全啟動、加密和 TPM 集成,提供現代安全模型,而不會犧牲太多效能或靈活性。