14.3.4. 關於快閃記憶體讀取保護的說明

在出廠狀態下,出貨的 OpenMV cam 上的韌體對任何能實際接觸到裝置的人來說都是可讀取的。攻擊者只要拿到 cam,就能將 SWD 探針接到除錯排針上,與 MCU 的除錯介面通訊,並傾印出快閃記憶體——其中包含每一個凍結的 Python 模組以及 ROMFS 分割區的內容。原廠 OpenMV 韌體預設不會啟用快閃記憶體讀取保護。

本頁明確記載這一點,讓正在出貨產品的團隊清楚知道責任歸屬。

14.3.4.1. cam 預設的行為

cam 的開機載入程式與執行環境不會開啟底層 MCU 的任何讀取保護功能。除錯介面維持開放,快閃記憶體維持可讀取,整個建置就如同在開發者工作檯上一樣運作。對於本教學的目標讀者而言,這是正確的預設值——一個出貨時就開啟讀取保護的 cam,就是一個無法透過 IDE 重新燒錄、在部署失敗後無法重新製作映像、也無法被建置團隊以外任何人挽救的 cam。

當 cam 從「開發者裝置」轉變為「產品」時,這個取捨就改變了。價值取決於應用程式碼保持私密的產品,必須自行啟用這項保護;OpenMV 韌體並不會代為處理。

14.3.4.2. 產品團隊要做的事

每一家 MCU 廠商都提供讀取保護機制。細節各有不同——位元層級的熔絲、一次性的生命週期轉換、簽章的快閃記憶體映像——但常見的形式大致是:

  • 將某個廠商特定的位元(或一組位元)寫入晶片,通常是透過廠商工具最後一次與 MCU 的除錯埠通訊來完成。

  • 寫入之後,除錯埠便拒絕讀取快閃記憶體。cam 仍然能開機並執行應用程式;它只是不再向探針暴露自身的內容。

  • 這項寫入是不可逆的。除了將 cam 銷毀之外,沒有任何辦法能讓它恢復到可除錯的狀態。

設定這項功能視 MCU 而定,步驟取決於 cam 上要保護的零件。廠商的參考手冊才是權威依據;在量產線上要做對,廠商支援是該走的管道。

這是容易的部分。

困難的部分在於封閉攻擊者用來在 cam 上執行程式碼、或讀取應用程式正在做什麼的每一條其他途徑。讀取保護只能阻止除錯探針傾印快閃記憶體。cam 還必須封閉:

  • MicroPython REPL。透過 USB 連接的 REPL 會接受任意的 Python 程式碼。讀取保護並不會改變這一點。一個 REPL 工作階段可以讀取 RAM、呼叫函式、外洩執行中應用程式所能看見的任何東西——實際上,一個可觸及的 REPL 會繞過讀取保護所換來的一切。停用 REPL 存取是產品團隊要負責的韌體建置變更。

  • IDE 指令碼上傳。IDE 的「在 cam 上執行此指令碼」途徑,所使用的 USB 協定介面與 REPL 相同。封閉 REPL 也會一併封閉這條途徑;只要其中任一條保持開放,就會在 cam 中留下一條可執行任意程式碼的通道。

  • 從檔案系統劫持進入點。當應用程式透過 將指令碼凍結進韌體 出貨時,這條途徑就已封閉——執行環境會在任何檔案系統複本之前先解析凍結的 boot.pymain.py,因此放在快閃記憶體或 SD 上的任何檔案都無法覆寫它們。一旦應用程式進入建置中,這項保護就是免費的。

  • 較新 cam 上的外部快閃記憶體。將應用程式映像儲存在外部快閃記憶體的 cam,會把該映像放在 PCB 上一顆顯而易見的晶片上;這顆晶片可以被拆焊下來,用市售工具直接讀取,或在原位透過探測匯流排來讀取。要保護它,需要開啟在讀取時解密快閃記憶體內容的晶片內硬體、產生加密金鑰、將該金鑰佈建到 cam 上,並將其不可逆地燒入 MCU 的一次性可程式化儲存區。這每一項都是各自獨立的一次性操作,而其中任何一項在量產單元上做錯,都會讓該單元變磚。

這份清單上的每一個項目,本身就是一整疊的韌體建置工作、量產線步驟與不可逆的寫入。一個真正鎖死的產品,意味著一份客製化的韌體建置、一個客製化的開機載入程式、一套為每個單元佈建金鑰的量產流程,以及一組在單元出線之前證明鎖確實已關閉的測試。那是以月為單位的工作量,而非以天計,而且不可逆性意味著犯錯的代價要以單元計。

為何預設是開放的

這份清單也說明了為何原廠 OpenMV 韌體出貨時不會啟用讀取保護。一個關閉了 REPL、停用了 IDE 指令碼上傳、且韌體已鎖死的 cam,是一個根本無法在其上開發的 cam——一開始讓 OpenMV cam 好用的整套工作流程都將不復存在。預設讓一切保持開放;產品團隊在邁向出貨單元的路上,自行選擇要關閉哪些部分。

14.3.4.3. 實際接觸仍能換到什麼

即使開啟了讀取保護,握有 cam 的攻擊者仍然能做不少事:

  • 藉由嗅探 cam 的輸出,重播它的網路流量。

  • 觀察它可見的行為,並推測它對輸入的反應。

  • 在某些情況下,透過針對受保護 MCU 量身打造的故障注入或旁通道攻擊來復原機密。

讀取保護提高了取得應用程式原始碼的成本。它並不會消除這個成本。「實際接觸=被攻陷」是安全審查應該從之出發的工作假設;保護機制只是決定了這個攻陷在時間與設備上要付出多少代價。

14.3.4.4. OpenMV 韌體出貨時的狀態

做個總結,讓內容更具體:

  • 預設不啟用讀取保護。

  • 原廠韌體中沒有可開啟它的建置旗標。

  • 沒有可從 MicroPython 呼叫的應用層 API。

需要這項保護的產品要出貨客製化韌體。該客製化存在於開發板的開機載入程式與量產流程之中,位於 OpenMV 程式碼庫之外。首次進行這項工作的團隊,應將其當作一塊獨立的工作項目納入開發時程規劃,而非當作最後才要補上的東西——不可逆性使得「晚點再加」的代價十分高昂。