UBIFS 認證支援¶
簡介¶
UBIFS 利用 fscrypt 框架為檔案內容和檔名提供保密性。 這可以防止攻擊者在單個時間點讀取檔案系統內容。 一個典型的例子是丟失的智慧手機,攻擊者無法在沒有檔案系統解密金鑰的情況下讀取裝置上儲存的個人資料。
然而,在當前狀態下,UBIFS 加密並不能阻止攻擊者修改檔案系統內容,然後使用者使用該裝置的情況。 在這種情況下,攻擊者可以任意修改檔案系統內容而無需使用者注意。 一個例子是修改二進位制檔案以在執行時執行惡意操作 [DMC-CBC-ATTACK]。 由於 UBIFS 的大多數檔案系統元資料都以明文形式儲存,因此可以很容易地交換檔案並替換其內容。
其他全盤加密系統(如 dm-crypt)涵蓋所有檔案系統元資料,這使得此類攻擊更加複雜,但並非不可能。 特別是,如果攻擊者可以在多個時間點訪問裝置。 對於 dm-crypt 和其他基於 Linux 塊 IO 層的的檔案系統,可以使用 dm-integrity 或 dm-verity 子系統 [DM-INTEGRITY, DM-VERITY] 在塊層獲得完整的資料認證。 這些也可以與 dm-crypt 結合使用 [CRYPTSETUP2]。
本文件描述了一種獲取檔案內容_和_完整元資料認證的 UBIFS 方法。 由於 UBIFS 使用 fscrypt 進行檔案內容和檔名加密,因此認證系統可以與 fscrypt 相關聯,以便可以利用金鑰派生等現有功能。 然而,也可以在不使用加密的情況下使用 UBIFS 認證。
MTD、UBI & UBIFS¶
在 Linux 上,MTD(記憶體技術裝置)子系統提供了一個統一的介面來訪問原始快閃記憶體裝置。 UBI(未排序塊映象)是在 MTD 之上工作的更重要的子系統之一。 它為快閃記憶體裝置提供卷管理,因此在某種程度上類似於塊裝置的 LVM。 此外,它還處理快閃記憶體特定的損耗均衡和透明 I/O 錯誤處理。 UBI 為其上層提供邏輯擦除塊 (LEB),並將它們透明地對映到快閃記憶體上的物理擦除塊 (PEB)。
UBIFS 是一個用於原始快閃記憶體的檔案系統,它在 UBI 之上執行。 因此,損耗均衡和一些快閃記憶體特性留給了 UBI,而 UBIFS 則專注於可擴充套件性、效能和可恢復性。
+------------+ +*******+ +-----------+ +-----+
| | * UBIFS * | UBI-BLOCK | | ... |
| JFFS/JFFS2 | +*******+ +-----------+ +-----+
| | +-----------------------------+ +-----------+ +-----+
| | | UBI | | MTD-BLOCK | | ... |
+------------+ +-----------------------------+ +-----------+ +-----+
+------------------------------------------------------------------+
| MEMORY TECHNOLOGY DEVICES (MTD) |
+------------------------------------------------------------------+
+-----------------------------+ +--------------------------+ +-----+
| NAND DRIVERS | | NOR DRIVERS | | ... |
+-----------------------------+ +--------------------------+ +-----+
Figure 1: Linux kernel subsystems for dealing with raw flash
在內部,UBIFS 維護多個持久儲存在快閃記憶體上的資料結構
索引:一個在快閃記憶體上的 B+ 樹,其中葉節點包含檔案系統資料
日誌:一個額外的資料結構,用於在更新快閃記憶體上的索引之前收集 FS 更改並減少快閃記憶體損耗。
樹節點快取 (TNC):一個記憶體中的 B+ 樹,反映當前的 FS 狀態,以避免頻繁的快閃記憶體讀取。 它基本上是索引的記憶體表示,但包含其他屬性。
LEB 屬性樹 (LPT):一個快閃記憶體上的 B+ 樹,用於每個 UBI LEB 的可用空間計算。
在本節的其餘部分,我們將更詳細地介紹快閃記憶體上的 UBIFS 資料結構。 TNC 在這裡不太重要,因為它永遠不會直接持久化到快閃記憶體上。 有關 UBIFS 的更多詳細資訊,請參見 [UBIFS-WP]。
UBIFS 索引 & 樹節點快取¶
基本的快閃記憶體上的 UBIFS 實體稱為節點。 UBIFS 知道不同型別的節點。 例如,資料節點(struct ubifs_data_node),它儲存檔案內容的塊,或 inode 節點(struct ubifs_ino_node),它表示 VFS inode。 幾乎所有型別的節點都共享一個公共標頭(ubifs_ch),其中包含基本資訊,如節點型別、節點長度、序列號等(請參見核心原始碼中的 fs/ubifs/ubifs-media.h)。 例外情況是 LPT 的條目和一些不太重要的節點型別,如填充節點,用於填充 LEB 末尾的不可用內容。
為了避免在每次更改時重新寫入整個 B+ 樹,它被實現為遊蕩樹,其中只有更改的節點被重新寫入,並且它們的先前版本被廢棄,而不會立即擦除它們。 因此,索引不是儲存在快閃記憶體上的單個位置,而是遊蕩的,並且只要包含它們的 LEB 沒有被 UBIFS 重用,快閃記憶體上就會有廢棄的部分。 為了找到索引的最新版本,UBIFS 將一個名為主節點的特殊節點儲存到 UBI LEB 1 中,該節點始終指向 UBIFS 索引的最新根節點。 為了可恢復性,主節點還會被複制到 LEB 2。 因此,掛載 UBIFS 只是簡單地讀取 LEB 1 和 2 以獲取當前主節點,並從那裡獲取最新快閃記憶體索引的位置。
TNC 是快閃記憶體上索引的記憶體表示。 它包含每個節點的一些額外的執行時屬性,這些屬性不會持久化。 其中之一是一個髒標誌,用於標記下次將索引寫入快閃記憶體時必須持久化的節點。 TNC 充當寫回快取,並且對快閃記憶體上索引的所有修改都透過 TNC 完成。 像其他快取一樣,TNC 不必將完整索引映象到記憶體中,而是在需要時從快閃記憶體讀取它的部分內容。 提交是 UBIFS 更新快閃記憶體上檔案系統結構(如索引)的操作。 在每次提交時,標記為髒的 TNC 節點都會被寫入快閃記憶體以更新持久化的索引。
日誌¶
為了避免磨損快閃記憶體,只有在滿足某些條件時才會持久化(提交)索引(例如,fsync(2))。 日誌用於記錄索引提交之間的任何更改(以 inode 節點、資料節點等形式)。 在掛載期間,從快閃記憶體讀取日誌並將其重放到 TNC 上(這將根據需要在快閃記憶體上索引建立)。
UBIFS 為日誌保留了一堆 LEB,稱為日誌區域。 日誌區域 LEB 的數量是在檔案系統建立時配置的(使用 mkfs.ubifs)並存儲在超級塊節點中。 日誌區域僅包含兩種型別的節點:引用節點和提交開始節點。 每當執行索引提交時,都會寫入提交開始節點。 引用節點在每次日誌更新時寫入。 每個引用節點都指向快閃記憶體上其他節點(inode 節點、資料節點等)的位置,這些節點是此日誌條目的一部分。 這些節點稱為芽,並描述了實際的檔案系統更改,包括它們的資料。
日誌區域被維護為一個環。 每當日誌幾乎已滿時,就會啟動提交。 這也會寫入提交開始節點,以便在掛載期間,UBIFS 將尋找最新的提交開始節點,並僅重放該節點之後的每個引用節點。 提交開始節點之前的每個引用節點都將被忽略,因為它們已經是快閃記憶體上索引的一部分。
在寫入日誌條目時,UBIFS 首先確保有足夠的空間來寫入此條目一部分的引用節點和芽。 然後,寫入引用節點,然後寫入描述檔案更改的芽。 在重放時,UBIFS 將記錄每個引用節點並檢查引用 LEB 的位置以發現芽。 如果這些損壞或丟失,UBIFS 將嘗試透過重新讀取 LEB 來恢復它們。 但是,這僅適用於日誌的最後一個引用的 LEB。 只有這一個 LEB 會因電源中斷而損壞。 如果恢復失敗,UBIFS 將無法掛載。 每個其他 LEB 的錯誤將直接導致 UBIFS 無法掛載操作。
| ---- LOG AREA ---- | ---------- MAIN AREA ------------ |
-----+------+-----+--------+---- ------+-----+-----+---------------
\ | | | | / / | | | \
/ CS | REF | REF | | \ \ DENT | INO | INO | /
\ | | | | / / | | | \
----+------+-----+--------+--- -------+-----+-----+----------------
| | ^ ^
| | | |
+------------------------+ |
| |
+-------------------------------+
Figure 2: UBIFS flash layout of log area with commit start nodes
(CS) and reference nodes (REF) pointing to main area
containing their buds
LEB 屬性樹/表¶
LEB 屬性樹用於儲存每個 LEB 的資訊。 這包括 LEB 型別和可用以及髒(舊的、廢棄的內容)空間量[1] 在 LEB 上。 型別很重要,因為 UBIFS 永遠不會在單個 LEB 上混合索引節點和資料節點,因此每個 LEB 都有特定的用途。 這對於可用空間計算也很有用。 有關更多詳細資訊,請參見 [UBIFS-WP]。
LEB 屬性樹再次是一個 B+ 樹,但它比索引小得多。 由於其尺寸較小,因此每次提交時總是作為一個塊寫入。 因此,儲存 LPT 是一項原子操作。
UBIFS 認證¶
本章介紹 UBIFS 認證,它使 UBIFS 能夠驗證儲存在快閃記憶體上的元資料和檔案內容的真實性和完整性。
威脅模型¶
UBIFS 認證支援檢測離線資料修改。 雖然它不能阻止它,但它使(受信任的)程式碼能夠檢查快閃記憶體上檔案內容和檔案系統元資料的完整性和真實性。 這涵蓋了檔案內容被交換的攻擊。
UBIFS 認證不會防止完整快閃記憶體內容的回滾。 也就是說,攻擊者仍然可以轉儲快閃記憶體並在以後恢復它而不會被檢測到。 它也不會防止單個索引提交的部分回滾。 這意味著攻擊者能夠部分撤消更改。 這是可能的,因為 UBIFS 不會立即覆蓋索引樹或日誌的廢棄版本,而是將它們標記為廢棄,並且垃圾回收會在稍後擦除它們。 攻擊者可以透過擦除當前樹的部分內容並恢復仍然在快閃記憶體上且尚未被擦除的舊版本來利用這一點。 這是可能的,因為每次提交都會始終寫入索引根節點和主節點的新版本,而不會覆蓋以前的版本。 UBI 的損耗均衡操作進一步幫助了這一點,它將內容從一個物理擦除塊複製到另一個物理擦除塊,並且不會原子地擦除第一個擦除塊。
如果攻擊者能夠在提供身份驗證金鑰後在裝置上執行程式碼,則 UBIFS 身份驗證不會涵蓋此類攻擊。 必須採取其他措施,如安全啟動和可信啟動,以確保只有受信任的程式碼才能在裝置上執行。
認證¶
為了能夠完全信任從快閃記憶體讀取的資料,所有儲存在快閃記憶體上的 UBIFS 資料結構都經過身份驗證。 那就是
索引,其中包括檔案內容、檔案元資料(如擴充套件屬性、檔案長度等)。
日誌,它還包含檔案內容和元資料,透過記錄對檔案系統的更改
LPT,它儲存 UBI LEB 元資料,UBIFS 使用該元資料進行可用空間計算
索引認證¶
透過 UBIFS 的遊蕩樹概念,它已經注意只更新和持久化從葉節點到完整 B+ 樹的根節點的更改部分。 這使我們能夠使用每個節點子節點的雜湊來增強樹的索引節點。 因此,索引基本上也是一棵 Merkle 樹。 由於索引的葉節點包含實際的檔案系統資料,因此它們的父索引節點的雜湊值涵蓋了所有檔案內容和檔案元資料。 當檔案更改時,UBIFS 索引會相應地從葉節點到根節點(包括主節點)進行更新。 可以掛鉤此過程以僅同時為每個更改的節點重新計算雜湊。 每當讀取檔案時,UBIFS 可以驗證從每個葉節點到根節點的雜湊,以確保節點的完整性。
為了確保整個索引的真實性,UBIFS 主節點儲存了一個金鑰雜湊 (HMAC),該雜湊包含它自己的內容和索引樹根節點的雜湊。 如上所述,每當索引被持久化時(即,在索引提交時),主節點總是被寫入快閃記憶體。
使用此方法,只會更改 UBIFS 索引節點和主節點以包含雜湊。 所有其他型別的節點將保持不變。 這減少了儲存開銷,這對 UBIFS 的使用者(即嵌入式裝置)來說是寶貴的。
+---------------+
| Master Node |
| (hash) |
+---------------+
|
v
+-------------------+
| Index Node #1 |
| |
| branch0 branchn |
| (hash) (hash) |
+-------------------+
| ... | (fanout: 8)
| |
+-------+ +------+
| |
v v
+-------------------+ +-------------------+
| Index Node #2 | | Index Node #3 |
| | | |
| branch0 branchn | | branch0 branchn |
| (hash) (hash) | | (hash) (hash) |
+-------------------+ +-------------------+
| ... | ... |
v v v
+-----------+ +----------+ +-----------+
| Data Node | | INO Node | | DENT Node |
+-----------+ +----------+ +-----------+
Figure 3: Coverage areas of index node hash and master node HMAC
對於穩健性和斷電安全性來說,最重要的部分是原子地持久化雜湊和檔案內容。 在這裡,現有的 UBIFS 邏輯如何持久化更改的節點已經為此目的而設計,以便 UBIFS 可以在發生斷電時安全地恢復。 向索引節點新增雜湊不會改變這一點,因為每個雜湊將與其各自的節點原子地一起持久化。
日誌認證¶
日誌也被認證。 由於日誌是持續寫入的,因此也有必要經常向日誌新增認證資訊,以便在發生斷電時,不會有太多資料無法認證。 這是透過從提交開始節點開始,在先前的引用節點、當前引用節點和芽節點上建立一個連續的雜湊來完成的。 不時地,只要合適,就在芽節點之間新增認證節點。 這種新的節點型別包含一個 HMAC,它包含雜湊鏈的當前狀態。 這樣,就可以將日誌認證到最後一個認證節點。 日誌的尾部可能沒有認證節點,因此無法認證,並且在日誌重放期間會被跳過。
我們得到這張用於日誌認證的圖片
,,,,,,,,
,......,...........................................
,. CS , hash1.----. hash2.----.
,. | , . |hmac . |hmac
,. v , . v . v
,.REF#0,-> bud -> bud -> bud.-> auth -> bud -> bud.-> auth ...
,..|...,...........................................
, | ,
, | ,,,,,,,,,,,,,,,
. | hash3,----.
, | , |hmac
, v , v
, REF#1 -> bud -> bud,-> auth ...
,,,|,,,,,,,,,,,,,,,,,,
v
REF#2 -> ...
|
V
...
由於雜湊還包括引用節點,因此攻擊者無法重新排序或跳過任何日誌頭以進行重放。 攻擊者只能從日誌的末尾刪除芽節點或引用節點,從而有效地將檔案系統倒回到最多最後一個提交。
日誌區域的位置儲存在主節點中。 由於主節點如上所述使用 HMAC 進行認證,因此無法篡改它而不被檢測到。 日誌區域的大小是在使用 mkfs.ubifs 建立檔案系統時指定的,並存儲在超級塊節點中。 為了避免篡改此值和儲存在那裡的其他值,HMAC 被新增到超級塊結構中。 超級塊節點儲存在 LEB 0 中,並且僅在功能標誌或類似更改時才會被修改,而不是在檔案更改時。
LPT 認證¶
快閃記憶體上 LPT 根節點的位置儲存在 UBIFS 主節點中。 由於 LPT 在每次提交時都會原子地寫入和讀取,因此無需認證樹的各個節點。 透過儲存在主節點中的簡單雜湊來保護完整 LPT 的完整性就足夠了。 由於主節點本身經過認證,因此可以透過驗證主節點的真實性並將儲存在那裡的 LTP 雜湊與從讀取的快閃記憶體上 LPT 計算出的雜湊進行比較來驗證 LPT 的真實性。
金鑰管理¶
為了簡單起見,UBIFS 認證使用單個金鑰來計算超級塊、主節點、提交開始節點和引用節點的 HMAC。 此金鑰必須在建立檔案系統時可用(mkfs.ubifs)以認證超級塊節點。 此外,它必須在掛載檔案系統時可用,以驗證認證的節點併為更改生成新的 HMAC。
UBIFS 認證旨在與 UBIFS 加密 (fscrypt) 並行執行,以提供保密性和真實性。 由於 UBIFS 加密對每個目錄都有不同的加密策略,因此可能有多個 fscrypt 主金鑰,並且可能存在沒有加密的資料夾。 另一方面,UBIFS 認證採用全有或全無的方法,因為它要麼認證檔案系統的所有內容,要麼不認證任何內容。 因此,並且因為 UBIFS 認證也應該在沒有加密的情況下使用,它不與 fscrypt 共享相同的主金鑰,而是管理專用的認證金鑰。
提供身份驗證金鑰的 API 尚未定義,但金鑰可以由使用者空間透過類似於當前在 fscrypt 中完成的方式的金鑰環提供。 然而,應該注意的是,當前的 fscrypt 方法已經顯示出它的缺陷,使用者空間 API 最終會改變 [FSCRYPT-POLICY2]。
儘管如此,使用者仍然可以在使用者空間中提供一個涵蓋 UBIFS 認證和加密的單個密碼或金鑰。 這可以透過相應的使用者空間工具來解決,這些工具除了用於加密的派生的 fscrypt 主金鑰之外,還會為認證派生第二個金鑰。
為了能夠檢查掛載時是否提供了正確的金鑰,UBIFS 超級塊節點還將儲存身份驗證金鑰的雜湊。 這種方法類似於為 fscrypt 加密策略 v2 提出的方法 [FSCRYPT-POLICY2]。
未來擴充套件¶
在某些情況下,供應商想要向客戶提供經過認證的檔案系統映象,可以這樣做而無需共享秘密的 UBIFS 認證金鑰。 相反,除了每個 HMAC 之外,還可以儲存一個數字簽名,其中供應商與檔案系統映象一起共享公鑰。 如果此檔案系統必須在之後進行修改,UBIFS 可以在第一次掛載時將所有數字簽名與 HMAC 交換,類似於 IMA/EVM 子系統處理此類情況的方式。 然後必須以正常方式預先提供 HMAC 金鑰。
參考¶
[CRYPTSETUP2] https://www.saout.de/pipermail/dm-crypt/2017-November/005745.html
[DMC-CBC-ATTACK] https://www.jakoblell.com/blog/2013/12/22/practical-malleability-attack-against-cbc-encrypted-luks-partitions/
[DM-INTEGRITY] https://kernel.linux.club.tw/doc/Documentation/device-mapper/dm-integrity.rst
[DM-VERITY] https://kernel.linux.club.tw/doc/Documentation/device-mapper/verity.rst
[FSCRYPT-POLICY2] https://www.spinics.net/lists/linux-ext4/msg58710.html
[UBIFS-WP] http://www.linux-mtd.infradead.org/doc/ubifs_whitepaper.pdf