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