dm-verity

裝置對映器的“verity”目標透過使用核心加密 API 提供的加密摘要,為塊裝置提供透明的完整性檢查。此目標是隻讀的。

構建引數

<version> <dev> <hash_dev>
<data_block_size> <hash_block_size>
<num_data_blocks> <hash_start_block>
<algorithm> <digest> <salt>
[<#opt_params> <opt_params>]
<version>

這是磁碟雜湊格式的型別。

0 是 Chromium OS 中使用的原始格式。

雜湊時附加鹽值,摘要連續儲存,塊的其餘部分用零填充。

1 是應在新裝置上使用的當前格式。

雜湊時預置鹽值,每個摘要用零填充到二的冪次。

<dev>

這是包含需要檢查完整性的資料的裝置。可以指定為路徑,如 /dev/sdaX,或裝置號,<major>:<minor>。

<hash_dev>

這是提供雜湊樹資料的裝置。可以類似於裝置路徑指定,也可以是同一裝置。如果使用同一裝置,則 hash_start 應位於配置的 dm-verity 裝置之外。

<data_block_size>

資料裝置上的塊大小,以位元組為單位。每個塊對應於雜湊裝置上的一個摘要。

<hash_block_size>

雜湊塊的大小,以位元組為單位。

<num_data_blocks>

資料裝置上的資料塊數量。附加塊不可訪問。您可以將雜湊值放在與資料相同的分割槽上,在這種情況下,雜湊值放置在 <num_data_blocks> 之後。

<hash_start_block>

這是從 hash_dev 的開頭到雜湊樹的根塊的偏移量,以 <hash_block_size> 塊為單位。

<algorithm>

用於此裝置的加密雜湊演算法。這應該是演算法的名稱,如“sha1”。

<digest>

根雜湊塊和鹽值的加密雜湊的十六進位制編碼。此雜湊應被信任,因為在此之後沒有其他認證。

<salt>

鹽值的十六進位制編碼。

<#opt_params>

可選引數的數量。如果沒有可選引數,可以跳過可選引數部分,或者 #opt_params 可以為零。否則 #opt_params 是後面引數的數量。

可選引數部分的示例

1 ignore_corruption

ignore_corruption

記錄損壞的塊,但允許讀取操作正常進行。

restart_on_corruption

發現損壞的塊時重啟系統。此選項與 ignore_corruption 不相容,並且需要使用者空間支援以避免重啟迴圈。

panic_on_corruption

發現損壞的塊時使裝置崩潰。此選項與 ignore_corruption 和 restart_on_corruption 不相容。

restart_on_error

檢測到 I/O 錯誤時重啟系統。此選項可以與 restart_on_corruption 選項結合使用。

panic_on_error

檢測到 I/O 錯誤時使裝置崩潰。此選項與 restart_on_error 選項不相容,但可以與 panic_on_corruption 選項結合使用。

ignore_zero_blocks

不驗證預期包含零的塊,並始終返回零。如果分割槽包含未使用的塊且不保證包含零,這可能很有用。

use_fec_from_device <fec_dev>

如果雜湊驗證失敗,使用前向糾錯(FEC)從損壞中恢復。使用指定裝置的編碼資料。這可能是資料和雜湊塊所在的同一裝置,在這種情況下,fec_start 必須位於資料和雜湊區域之外。

如果編碼資料包含附加元資料,則必須在雜湊塊之後在雜湊裝置上可訪問。

注意:資料和雜湊裝置的塊大小必須匹配。此外,如果 verity <dev> 已加密,則 <fec_dev> 也應加密。

fec_roots <num>

生成器根的數量。這等於編碼資料中奇偶校驗位元組的數量。例如,在 RS(M, N) 編碼中,根的數量是 M-N。

fec_blocks <num>

FEC 裝置上編碼資料塊的數量。FEC 裝置的塊大小是 <data_block_size>。

fec_start <offset>

這是從 FEC 裝置開始到編碼資料開始的偏移量,以 <data_block_size> 塊為單位。

check_at_most_once

僅在資料塊第一次從資料裝置讀取時進行驗證,而不是每次讀取時都驗證。這減少了 dm-verity 的開銷,使其可以在記憶體和/或 CPU 受限的系統上使用。但是,它提供的安全性級別較低,因為只會檢測資料裝置內容的離線篡改,而不是線上篡改。

雜湊塊每次從雜湊裝置讀取時仍會被驗證,因為雜湊塊的驗證不如資料塊的效能關鍵,並且在它覆蓋的所有資料塊都被驗證之後,雜湊塊將不再被驗證。

root_hash_sig_key_desc <key_description>

這是 USER_KEY 的描述,核心將查詢該金鑰以獲取根雜湊的 pkcs7 簽名。pkcs7 簽名用於在建立裝置對映器塊裝置期間驗證根雜湊。根雜湊的驗證取決於核心中是否設定了 config DM_VERITY_VERIFY_ROOTHASH_SIG。預設情況下,簽名會根據內建的可信金鑰環進行檢查,如果設定了 DM_VERITY_VERIFY_ROOTHASH_SIG_SECONDARY_KEYRING,則會根據輔助可信金鑰環進行檢查。輔助可信金鑰環預設包含內建的可信金鑰環,如果它們由輔助可信金鑰環中已有的證書籤名,則它也可以在執行時獲得新證書。

try_verify_in_tasklet

如果 verity 雜湊在快取中且 I/O 大小不超過限制,則在下半部分而不是工作佇列中驗證資料塊。此選項可以減少 I/O 延遲。大小限制可以透過 /sys/module/dm_verity/parameters/use_bh_bytes 配置。這四個引數依次對應 IOPRIO_CLASS_NONE、IOPRIO_CLASS_RT、IOPRIO_CLASS_BE 和 IOPRIO_CLASS_IDLE 的限制。例如:<none>,<rt>,<be>,<idle> 4096,4096,4096,4096

操作理論

dm-verity 旨在作為經過驗證的引導路徑的一部分進行設定。這可以是任何操作,從使用 tboot 或 trustedgrub 引導到僅從已知良好裝置(如 USB 驅動器或 CD)引導。

配置 dm-verity 裝置時,呼叫者應已透過某種方式(加密簽名等)進行了身份驗證。例項化後,所有雜湊將在磁碟訪問期間按需驗證。如果它們無法驗證到樹的根節點(即根雜湊),則 I/O 將失敗。這應該能檢測到裝置上任何資料和雜湊資料的篡改。

加密雜湊用於按塊斷言裝置的完整性。這允許在第一次讀取到頁快取時進行輕量級雜湊計算。塊雜湊線性儲存,並對齊到最接近的塊大小。

如果啟用了前向糾錯(FEC)支援,任何損壞資料的恢復都將使用相應資料的加密雜湊進行驗證。這就是為什麼將糾錯與完整性檢查結合起來至關重要。

雜湊樹

樹中的每個節點都是一個加密雜湊。如果它是葉節點,則計算磁碟上某個資料塊的雜湊。如果它是中間節點,則計算多個子節點的雜湊。

樹中的每個條目都是一組相鄰節點,它們適合一個塊。數量根據 block_size 和所選加密摘要演算法的大小確定。雜湊值在此條目中線性排序,任何未對齊的尾隨空間都將被忽略,但在計算父節點時會包含在內。

樹看起來像這樣

alg = sha256, num_blocks = 32768, block_size = 4096

                            [   root    ]
                           /    . . .    \
                [entry_0]                 [entry_1]
               /  . . .  \                 . . .   \
    [entry_0_0]   . . .  [entry_0_127]    . . . .  [entry_1_127]
      / ... \             /   . . .  \             /           \
blk_0 ... blk_127  blk_16256   blk_16383      blk_32640 . . . blk_32767

磁碟格式

verity 核心程式碼不讀取磁碟上的 verity 元資料頭。它只讀取緊隨其後的雜湊塊。使用者空間工具應驗證 verity 頭的完整性。

或者,可以省略頭,並透過核心命令列傳遞 dmsetup 引數,在受信任的鏈中驗證命令列。

緊隨頭之後(並按扇區號填充到下一個雜湊塊邊界)是雜湊塊,它們按深度儲存(從根開始),並按索引遞增的順序排序。

核心引數和磁碟元資料格式的完整規範可在 cryptsetup 專案的 wiki 頁面上找到

狀態

如果到目前為止執行的每個檢查都有效,則返回 V(表示有效)。如果任何檢查失敗,則返回 C(表示損壞)。

示例

設定裝置

# dmsetup create vroot --readonly --table \
  "0 2097152 verity 1 /dev/sda1 /dev/sda2 4096 4096 262144 1 sha256 "\
  "4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076 "\
  "1234000000000000000000000000000000000000000000000000000000000000"

有一個命令列工具 veritysetup 可用於計算或驗證雜湊樹或啟用核心裝置。這可從 cryptsetup 上游倉庫 https://gitlab.com/cryptsetup/cryptsetup/ 獲取(作為 libcryptsetup 擴充套件)。

在裝置上建立雜湊

# veritysetup format /dev/sda1 /dev/sda2
...
Root hash: 4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076

啟用裝置

# veritysetup create vroot /dev/sda1 /dev/sda2 \
  4392712ba01368efdf14b05c76f9e4df0d53664630b5d48632ed17a137f39076