Google致力於提高黑人社區的種族平等。 怎麼看。
本頁面由 Cloud Translation API 翻譯而成。
Switch to English

實施dm-verity

Android 4.4及更高版本通過可選的device-mapper-verity(dm-verity)內核功能支持“驗證啟動”,該功能可對塊設備進行透明的完整性檢查。 dm-verity有助於防止持久化的rootkit可以保留root特權並損害設備。此功能可幫助Android用戶確保在啟動設備時與上次使用設備處於同一狀態。

具有root特權的潛在有害應用程序(PHA)可以從檢測程序中隱藏,否則可能會掩蓋自己。生根軟件可以執行此操作,因為它通常比檢測器具有更高的特權,從而使該軟件可以“欺騙”檢測程序。

dm-verity功能使您可以查看塊設備(文件系統的基礎存儲層),並確定其是否與期望的配置相匹配。它使用加密哈希樹來執行此操作。對於每個塊(通常為4k),都有一個SHA256哈希。

因為哈希值存儲在頁面樹中,所以只有頂級“根”哈希必須受信任才能驗證樹的其餘部分。修改任何塊的能力等同於破壞密碼哈希。有關此結構的描述,請參見下圖。

dm-verity哈希表

圖1. dm-verity哈希表

公用分區包含在引導分區上,必須由設備製造商從外部進行驗證。該密鑰用於驗證該哈希的簽名,並確認設備的系統分區受保護且未更改。

操作方式

dm-verity保護存在於內核中。因此,如果生根軟件在內核出現之前危害了系統,它將保留該訪問權限。為了減輕這種風險,大多數製造商使用設備中燒錄的密鑰來驗證內核。設備出廠後,該密鑰不可更改。

製造商使用該密鑰來驗證一級引導加載程序上的簽名,而後者又會在後續級別,應用程序引導加載程序以及最終內核上驗證簽名。每個希望利用經過驗證的引導的製造商都應該有一種驗證內核完整性的方法。假設內核已經過驗證,內核可以查看塊設備並在掛載時對其進行驗證。

驗證塊設備的一種方法是直接哈希其內容並將它們與存儲的值進行比較。但是,嘗試驗證整個塊設備可能會花費很長時間,並且會消耗大量設備功率。設備將需要很長時間才能啟動,然後在使用前需要大量消耗。

相反,dm-verity僅在訪問每個塊時才單獨驗證塊。當讀入內存時,該塊將並行散列。然後在樹上驗證哈希。並且由於讀取該塊是非常昂貴的操作,因此由該塊級別驗證引入的等待時間相對來說是標稱的。

如果驗證失敗,則設備將產生一個I / O錯誤,指示無法讀取該塊。就像預期的那樣,文件系統似乎已損壞。

應用程序可以選擇不使用結果數據進行操作,例如,當應用程序的主要功能不需要這些結果時。但是,如果應用程序無法在沒有數據的情況下繼續運行,它將失敗。

前向糾錯

Android 7.0及更高版本通過前向糾錯(FEC)改善了dm-verity魯棒性。 AOSP實現從常見的Reed-Solomon糾錯碼開始,並應用了一種稱為交織的技術來減少空間開銷並增加可以恢復的損壞塊的數量。有關FEC的更多詳細信息,請參閱帶有錯誤糾正的嚴格執行的驗證啟動

實作

摘要

  1. 生成ext4系統映像。
  2. 為該圖像生成哈希樹
  3. 為該哈希樹構建dm-verity表
  4. 在該dm-verity表上簽名以生成表簽名。
  5. 將表簽名和dm-verity表捆綁到verity元數據中。
  6. 連接系統映像,verity元數據和哈希樹。

有關哈希樹和dm-verity表的詳細說明,請參見Chromium項目-已驗證啟動

生成哈希樹

如引言中所述,哈希樹是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哈希。通過僅將那些SHA256哈希連接到4k塊中來形成第1層,從而生成更小的圖像。第2層的形成方式相同,但具有第1層的SHA256哈希值。

完成此操作,直到上一層的SHA256哈希可以放入單個塊中為止。當獲取該塊的SHA256時,便有了樹的根哈希。

哈希樹的大小(以及相應的磁盤空間使用情況)隨驗證分區的大小而變化。實際上,哈希樹的大小往往很小,通常小於30 MB。

如果某層中的某個塊沒有被上一層的哈希自然地完全填充,則應將其填充零以達到預期的4k。這使您知道哈希樹尚未刪除,而是由空白數據完成。

要生成哈希樹,請將第2層散列連接到第1層的散列上,將第3層散列連接到第2層的散列上,依此類推。將所有這些寫到磁盤上。請注意,這沒有引用根哈希的第0層。

回顧一下,構建哈希樹的通用算法如下:

  1. 選擇隨機鹽(十六進制編碼)。
  2. 將系統映像分解為4k塊。
  3. 對於每個塊,獲取其(加鹽的)SHA256哈希。
  4. 連接這些散列以形成一個級別
  5. 將0填充到4k塊邊界。
  6. 將級別連接到哈希樹。
  7. 使用上一個級別作為下一個級別的源重複步驟2-6,直到只有一個哈希為止。

這樣的結果是單個哈希,即您的根哈希。在構建dm-verity映射表時會使用此鹽和鹽。

建立dm-verity映射表

構建dm-verity映射表,該表標識內核的塊設備(或目標)以及哈希樹的位置(該值相同)。此映射用於fstab生成和引導。該表還標識了塊的大小以及hash_start(哈希樹的開始位置)(特別是從圖像開始的塊號)。

有關驗證目標映射表字段的詳細說明,請參見cryptsetup

簽署dm-verity表

在dm-verity表上簽名以生成表簽名。驗證分區時,首先驗證表簽名。這是針對引導映像上位於固定位置的鍵完成的。密鑰通常包含在製造商的構建系統中,用於自動包含在固定位置的設備中。

要使用此簽名和密鑰組合驗證分區:

  1. 將libmincrypt兼容格式的RSA-2048密鑰添加到/verity_key/boot分區。標識用於驗證哈希樹的密鑰的位置。
  2. 在相關條目的fstab中,將verify添加到fs_mgr標誌。

將表簽名捆綁到元數據中

將表簽名和dm-verity表捆綁到verity元數據中。對整個元數據塊進行版本控制,以便對其進行擴展,例如添加第二種簽名或更改某些順序。

作為健全性檢查,魔術數字與有助於識別表的每組表元數據相關聯。由於長度包含在ext4系統映像頭中,因此這提供了一種在不知道數據本身內容的情況下搜索元數據的方法。

這樣可以確保您沒有選擇驗證未驗證的分區。如果是這樣,則缺少此幻數將終止驗證過程。該數字類似於:
0xb001b001

十六進制的字節值為:

  • 第一個字節= b0
  • 第二個字節= 01
  • 第三個字節= b0
  • 第四個字節= 01

下圖描述了verity元數據的細分:

<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表表長度字節
填充此結構的0填充長度為32k 0

優化dm-verity

為了從dm-verity中獲得最佳性能,您應該:

  • 在內核中,為ARMv7打開NEON SHA-2,為ARMv8打開SHA-2擴展。
  • 使用不同的預讀和prefetch_cluster設置進行試驗,以找到適合您設備的最佳配置。