適用於新手的 Linux Flash 講解:Linux如何與Flash一起使用?

Keywords: dd; MTD; NAND Flash; Flash 讀寫測試;


本文介紹了 Linux 和在嵌入式設備上常用的 NAND 閃存,現在我們假設 NAND flash 有以下特性:

  • 它具有較大的擦除塊(數十KB)。
  • 它具有中等大小的編程頁面(大小爲KB幾個)。
  • 它可能具有子頁面(通常爲512個字節)。
  • 只能以頁面大小(或子頁面大小)的塊進行編程(將1更改爲零)。
  • 如果必須將某個位從零更改爲一,則必須擦除並重寫整個擦除塊。
  • 擦除塊的壽命有限(在擦除/編程週期中)。

此外,Linux使用MTD模塊處理閃存。MTD既不是塊設備也不是字符設備。閃存以較大的擦除塊進行處理,可以整體進行擦除和編程。這給它的處理帶來了一定的困難。無法使用傳統的文件系統(例如ext2),因爲閃存不提供按塊(小尺寸可隨機尋址)的訪問。這意味着您只能擦除整個塊,並且不能擦除其中的一部分。

構建基本的Linux Flash設備

在本練習中,我們將使用Linux的NAND模擬器,該模塊可讓您將RAM的一部分重新用作閃存設備。這對於測試和練習非常有用。儘管此“閃存”存儲器將是易失性的,但降級不會有任何問題,並且該模擬器可在Linux運行的任何地方使用。最終,我們將學習保存自己的圖像,因此波動不會成爲問題。

可以通過將“ nandsim”模塊加載到內核中來激活NAND仿真器。這可以通過以root身份運行 modprobe 來完成。在下面的示例中,我們正在模擬特定的閃存設備。

在這裏插入圖片描述

模擬器根據設備的ID字節確定要模擬的內容。這些字節描述了製造商,特性,擦除塊大小和設備的總內存大小。這些值應從閃存數據表中獲取。在我們的案例中,我們正在模擬一個具有128KB擦除塊的賽普拉斯(AKA Spansion)S43ML01G2 1Gbit NAND閃存。這給我們提供了128MB的工作空間。這些id字節在傳遞給nandsim的xxx_id_byte參數中可見。

在上面的示例中,我們還傳遞了“ parts”參數。這告訴模擬器將閃存設備劃分爲多個 /dev/mtdN 設備文件。使用真正的閃存設備,該分區數據將在啓動時傳遞到Linux內核。對閃存設備進行分區有助於隔離設備的不同部分,從而最大程度地降低風險。

假設我們將所有內容都放在同一個MTD分區中。在更新期間,我們將重新刷新整個設備,包括引導加載程序和Linux內核。一次雜散擦除,斷電或僅寫入錯誤的塊可能會覆蓋我們系統的重要部分,並使其完全無法使用。

相反,如果我們使用不同的MTD分區,則只會寫入應用程序分區,而不會影響內核和引導加載程序。停電可能仍然會損壞系統,但是我們可以使用初始引導加載程序通過TFTP恢復系統。如果我們刷新了整個設備,我們可能會用磚砌它,而沒有恢復的機會。

MTD分區非常普遍,並且如果可以訪問串行控制檯,通常可以恢復大多數磚塊設備。儘管在本練習中這與我們無關,但在確定如何劃分虛擬設備時仍應考慮到這一點。parts參數列出了每個分區的大小。如果剩餘空閒塊,則將它們分配給最終分區。對於我們的設備,我們需要以下分區:

n/a

此分區設置模仿典型的設備。有一個系統引導分區,引導加載程序(通常是uBoot)駐留在該分區中,我們很少接觸它。Linux內核有一個分區,還有一個大分區來保存其文件系統。此外,還有第二個引導加載程序,一個恢復系統(如果主系統不可引導,它將運行)和一個非易失性配置存儲。儘管我們不會用真實數據填充這些數據,但是這種設置是如此普遍,以至於當我們對真實系統進行逆向工程時,我們可能會看到類似的結構,因此熟悉它很重要。

加載模擬器(或真實的閃存驅動程序)後,我們可以 cat /proc/mtd 以查看MTD的狀態。

n/a

注意我們如何具有相同的結構。大小和擦除大小以十六進制表示。例如,20000h是十進制的128K。此外,總大小除以擦除大小會得出我們想要的擦除塊數。

我們還可以看到系統中發生了什麼變化。

n/a

對於每個MTD分區,系統都會創建一個 /dev/mtdX 和一個 /dev/mtdXro 設備。這些是各自的讀/寫和只讀版本。讓我們閱讀NVRAM分區:

n/a

分區已滿,就像在完全擦除的閃存設備中所期望的那樣。使用dd,我們可以讀取和創建MTD分區的映像。重要的是要記住,儘管這些設備顯示爲字符設備,但它們實際上是MTD。我們可以可靠地讀取它們,因爲讀取是它們的原語之一,但是使用 dd 寫入它們可能是不可靠的。理想情況下,我們不應將 dd 用於閃存輸入/輸出。因此,我們應該使用閃爍的工具對其進行寫操作,並使用轉儲工具從MTD中提取圖像。mtd-utils套件爲我們提供了一系列處理閃存的工具。特別是,我們將使用 nandwritenanddump 與Flash設備進行交互。

讓我們獲取一些隨機數據,並將其放入文件中,然後將其視爲模擬的引導加載程序。我們可以對其進行閃爍,重新閱讀,然後將其與原始圖像進行比較。

在這裏插入圖片描述

最後,我們可以使用 flash_erase 命令擦除閃存設備。通過選擇起始塊和計數,此命令用於擦除MTD分區中的特定擦除塊。該命令最常用於擦除整個分區,方法是選擇零作爲起始塊,選擇零作爲計數,並通過命令行按此順序傳遞。當用戶恢復出廠設置時,這通常在許多設備上發生。讓我們通過擦除引導加載程序分區來查看 flash_erase 的運行情況。

n/a

使用三個基本命令,我們能夠讀取,寫入和擦除MTD。我們應該記住,由於READ是有效的指令,因此可以在緊急情況下使用dd轉儲 /dev/mtdX。除非設備的壞塊無法再寫入或讀取,否則這將很好地工作。

MTDBlock設備

那麼,考慮到它們既不是純字符設備也不是純塊設備,我們可以使用 /dev/mtdX 做什麼呢?要掛載文件系統,至少在傳統意義上,我們需要一個塊設備,那麼如何從MTD中獲取一個呢?

所有這些問題的答案是利用mtdblock模塊。該模塊以最粗略的方式將常規MTD轉換爲塊設備:將塊映射到擦除塊的一部分,並且對於每個寫操作,擦除並重寫該擦除塊。此過程存在一些明顯的問題。一個字節的寫入操作可能最終會寫入一個完整的擦除塊(在我們的模擬器中爲128KB)。另外,沒有任何磨損平衡,並且塊被線性映射。如果我們一次向一個文件寫入10次,一次寫入一個字節(假設每次寫入後讓內核刷新數據),我們將最終擦除並重新編程擦除塊10次。重複此擦除/編程循環將最終使擦除塊耗盡,然後錯誤將無法恢復。

有幾種策略可以防止這種結果。首先,我們可以將文件系統視爲只讀文件,然後掛載虛擬磁盤並將其映射到文件系統中可變的部分。較舊的設備通常會這樣做,通常是在系統啓動期間加載閃存存儲的RomFS並將某些特定數據複製到ramdisk。該系統主要在RAM上運行,並且在關閉電源後重新啓動所有數據。用戶特定的配置通常存儲在其他閃存分區中。在我們的模擬系統中,它將是 /dev/mtd5。這種系統組織的優勢是極其耐用(幾乎不寫閃存),甚至可以將閃存設備設置爲只讀(甚至防止意外擦除),但是由於需要複製,文件系統設計更加複雜部分內存。

從安全角度來看,RomFS系統往往很難受到攻擊,因爲儘管它們可能具有使攻擊者獲得外殼的漏洞,但幾乎不可能永久地對其進行修改。由於每次重新啓動後系統都會還原到原始狀態,因此可以防止持久性後門。由於沒有刷新新的RomFS映像,威脅參與者必須在每次重新啓動後再次利用原始漏洞再次攻擊系統。另一方面,打補丁更加複雜,因此漏洞不會得到儘快處理。因此,攻擊者可能會發現,使用相同的攻擊來重新獲得對設備的控制權,可以更輕鬆地控制設備。

可以使用genromfs生成RomFS圖像,其方式類似於創建ISO映像。例如,我們已經生成了五個1MB的隨機文件,以模擬我們的恢復文件系統。然後,我們生成RomFS映像,然後將其閃存到恢復分區(mtd4)。我們還必須使用*-p*參數將文件系統填充到Easeblock大小的倍數。

n/a
n/a
n/a

請注意系統是隻讀的。我們的模擬系統必須將任何需要可變的數據複製到RamFS。在初始系統啓動腳本(如rc.local)中,通常將其視爲一系列cp命令。

另一種策略是使用具有介質意識的日記文件系統,例如JFFS2。該文件系統直接安裝在mtdblock上,幷包含有關閃存設備的足夠信息,以更均勻地分配磨損在不同塊之間的方式來知道將新信息寫入何處,從而避免消耗特定的塊。文件系統還必須自己處理壞塊。

該過程與RomFS相似,只是使用了mkfs.jffs2。在這種情況下,擦除塊的大小將傳遞到mkfs.jffs2,因爲它需要知道擦除塊的大小才能組織自己的日誌。與RomFS不同,可以寫入文件系統。

n/a

這主要是在第二代設備中完成的。這些設備現在具有讀/寫根文件系統,因此簡化了引導程序。該系統甚至可以在聯機時進行修補。這具有優點和缺點。安全補丁程序得到簡化,但是攻擊者也可以通過修改啓動腳本輕鬆地在系統中立足。

最後,儘管完全有可能在mtdblock上使用常規文件系統,但強烈建議不要這樣做。可以創建文件,並使用mkfs創建常規文件系統。但是,像以前一樣刷新和裝入文件將破壞某些擦除塊(主要是包含文件系統結構的擦除塊),並且可能會引起細微的錯誤,直到災難性地失敗爲止。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章