本文將討論在連接的設(shè)備中更新引導(dǎo)加載程序的問題。所討論的原則適用于任何軟件系統(tǒng),我們將專門討論運行 linux 的系統(tǒng)。
現(xiàn)代電子設(shè)備越來越復(fù)雜,并與互聯(lián)網(wǎng)連接。作為一般規(guī)則,復(fù)雜性與安全性背道而馳,不安全的互聯(lián)網(wǎng)連接設(shè)備已經(jīng)成熟,罪魁禍?zhǔn)卓梢詾E用。在設(shè)計這些系統(tǒng)時,我們必須假設(shè)所有軟件都會有錯誤,其中一些錯誤將是可利用的漏洞。解決這些問題的第一步是確保軟件更新可以傳送到您的系統(tǒng),最好是自動和無線 (OTA)。歐盟“消費者物聯(lián)網(wǎng)網(wǎng)絡(luò)安全:基線要求”標(biāo)準(zhǔn)草案 (ETSI EN 303 645),”具體包括及時、自動更新作為其要求之一。它確實為不可變的第一階段引導(dǎo)加載程序例外,以最大程度地降低現(xiàn)場設(shè)備處于非引導(dǎo)狀態(tài)(也稱為“磚塊 ”板)的風(fēng)險。
本文將討論更新連接設(shè)備中的引導(dǎo)加載程序的問題。請注意,雖然這里討論的原則適用于任何軟件系統(tǒng),但我們將專門討論運行 Linux 的系統(tǒng)。使用更小、更定制設(shè)計的系統(tǒng)可能會為這些系統(tǒng)提供更多獨特的選擇。
系統(tǒng)設(shè)計
圖 1 顯示了一個通用的 Linux 系統(tǒng),其中包含可能更新的主要組件。存儲介質(zhì)將是某種塊設(shè)備,例如 eMMC 或 SATA 硬盤驅(qū)動器。在該設(shè)備中,將有引導(dǎo)加載程序、內(nèi)核、設(shè)備樹(取決于所使用的 CPU)和包含構(gòu)建系統(tǒng)所需的所有文件的根文件系統(tǒng)。在某些情況下會使用更復(fù)雜的架構(gòu),但出于討論的目的,我們將其限制為最簡單的情況。
諸如 Mender 、 swupdate等系統(tǒng)更新實用程序能夠開箱即用地更新內(nèi)核、設(shè)備樹和根文件系統(tǒng),并且在許多情況下,這種級別的可更新性就足夠了。
引導(dǎo)加載程序是系統(tǒng)的組件,負責(zé)在上電時初始化系統(tǒng),從 CPU 復(fù)位指令開始。它負責(zé)以下任務(wù):
? 初始化和清理 RAM
? 將所有外設(shè)設(shè)置為已知的靜止?fàn)顟B(tài)以避免意外中斷。
? 加載并啟動 Linux 內(nèi)核
如前所述,所有軟件都有錯誤,因此我們可以假設(shè)也會有引導(dǎo)加載程序錯誤。我們可以通過最小化引導(dǎo)加載程序的功能來減少攻擊面,但是我們可以完全消除錯誤的風(fēng)險。為什么更新引導(dǎo)加載程序比更新系統(tǒng)的其他組件更復(fù)雜?如果我們嘗試有什么風(fēng)險?如果我們不嘗試會有什么風(fēng)險?
具有無線功能的系統(tǒng)
此框圖顯示了能夠進行強大的無線 (OTA) 更新的系統(tǒng)的基本系統(tǒng)設(shè)計。[4] 引導(dǎo)加載程序負責(zé)系統(tǒng)初始化并與 OTA 客戶端交互以選擇使用哪個內(nèi)核、設(shè)備樹和根文件系統(tǒng)。穩(wěn)健性是通過具有運行 Linux 映像所需的組件的完全冗余來提供的。這可確保在 OTA 更新中斷的情況下始終有一個已知良好的映像可以回滾。此外,這確保了完全原子更新,因為更新客戶端是系統(tǒng)中唯一知道更新正在進行中的組件,直到更新完成并準(zhǔn)備好運行。
OTA 更新的任何組件都可能導(dǎo)致設(shè)備無法正常工作,因此系統(tǒng)的穩(wěn)健性與引導(dǎo)加載程序處理回滾到先前已知良好配置的能力直接相關(guān)。這意味著系統(tǒng)中必須有一個組件,它是不可變的以正確處理錯誤的更新。
引導(dǎo)加載程序更新
在大多數(shù)情況下,處理回滾的不可變組件是引導(dǎo)加載程序。在一個典型的嵌入式 Linux 應(yīng)用程序中是Das U-Boot [5]。如果我們嘗試更新引導(dǎo)加載程序,由于沒有冗余,我們就有可能使我們的電路板變磚。如果在我們開始寫入新的引導(dǎo)加載程序映像之后,但在寫入完成之前,板電源循環(huán),那么我們的映像包含舊版本的一部分和新版本的一部分。這種情況下的行為是未定義的,唯一的緩解措施是能夠物理訪問設(shè)備以編寫正確的引導(dǎo)加載程序,通常使用 USB 或其他硬接線連接。
但是我們?yōu)槭裁匆乱龑?dǎo)加載程序呢?至少,引導(dǎo)加載程序只是用作初始化硬件然后將控制權(quán)交給 Linux 內(nèi)核的一種方式。由于功能有限,引導(dǎo)加載程序出現(xiàn)問題的風(fēng)險已降至最低。
對于許多設(shè)計,這種風(fēng)險水平是可以接受的,架構(gòu)師可以決定在其部署的設(shè)備中不提供 OTA 引導(dǎo)加載程序更新。作為最后的手段,仍然可以使用硬連線機制。
然而,對于許多設(shè)計來說,這種風(fēng)險水平被認為是不可接受的,并且必須為引導(dǎo)加載程序的 OTA 更新提供一些機制。此外,許多設(shè)計在引導(dǎo)加載程序中添加了更多功能;系統(tǒng)診斷或其他特定于應(yīng)用程序的要求可能會在引導(dǎo)加載程序中實現(xiàn),從而導(dǎo)致需要更新的可能性更大。那么我們該如何處理呢?
提供引導(dǎo)加載程序更新的選項
有許多選項可以更新引導(dǎo)加載程序。本討論并非旨在提供完整的解決方案,而是對可能適用于您的設(shè)計的方法進行高級描述。每個都有其權(quán)衡。
選項 1:無冗余
如果特定應(yīng)用程序可以接受磚塊板的風(fēng)險,那么您可以簡單地嘗試部署引導(dǎo)加載程序更新 OTA,并在它發(fā)生時處理后果。如果您的車隊規(guī)模很小,并且物理訪問設(shè)備的成本很低,那么這可能會很好。如果需要更新引導(dǎo)加載程序,并且 OTA 嘗試失敗,那么您的嘗試并不會更糟。OTA 引導(dǎo)加載程序更新失敗的情況與沒有 OTA 引導(dǎo)加載程序更新能力的情況相同。即,您必須獲得對設(shè)備的物理訪問權(quán)限并使用制造商提供的機制來重新刷新引導(dǎo)加載程序。
選項 2:多階段引導(dǎo)加載程序
此架構(gòu)將引導(dǎo)加載程序功能分為兩個階段(或更多階段,具體取決于您的設(shè)計的復(fù)雜性)。最終,這仍然需要在階段 1 中使用不可變的代碼。您在更新階段 2 時確實具有冗余性和穩(wěn)健性,因此如果您仔細選擇在何處實現(xiàn)功能,您可以提供引導(dǎo)加載程序功能的 OTA 更新。這是一個不錯的選擇,因為不可變的第一階段二進制文件中的代碼量減少了,從而降低了整體風(fēng)險。
U-Boot 使用 SPL(Secondary Program Loader)和 TPL(Tertiary Program Loader)實現(xiàn)多階段引導(dǎo)。引入此機制是為了支持具有單獨引導(dǎo) ROM 的系統(tǒng),這些引導(dǎo) ROM 太小而無法存儲完整的 U-Boot 映像。在這種情況下,U-Boot SPL 映像將包含足夠的初始化代碼來加載和啟動完整的 U-Boot 映像,通常來自 MMC 等大型塊設(shè)備。SPL 需要能夠初始化足夠的 RAM 和包含完整 U-Boot 映像的設(shè)備。
即使對于沒有小型引導(dǎo) ROM 限制的設(shè)備,我們也可以利用這種架構(gòu)在第 2 階段實現(xiàn)我們的可更新功能,同時在第 1 階段保留最低限度,包括正確處理冗余塊。
第 1 階段存在問題,需要物理訪問才能解決。鑒于第 1 階段的功能減少,在許多情況下,這種風(fēng)險水平是可以接受的。
選項 3:并行引導(dǎo)加載程序
許多板提供從多個設(shè)備啟動的能力。例如,許多板可以從板載 eMMC 或可移動 SD/MMC 卡啟動?;蛘?,他們可以為引導(dǎo)加載程序使用專用的 NOR 閃存設(shè)備,但仍然能夠從 eMMC 塊媒體運行引導(dǎo)加載程序。
這些類型的板可以配置為將不可變引導(dǎo)加載程序存儲在一個受支持的設(shè)備中,然后將 OTA 可更新引導(dǎo)加載程序存儲在另一個設(shè)備中。通常,可更新的引導(dǎo)加載程序與根文件系統(tǒng)位于相同的媒體(即 eMMC)中,因此很容易更新。由于“備用”媒體中的引導(dǎo)加載程序是不可變的,因此可以依靠它從“標(biāo)準(zhǔn)”位置的引導(dǎo)加載程序的損壞 OTA 更新中恢復(fù)。
這種方法的問題是引導(dǎo)設(shè)備的選擇通常需要物理訪問電路板以移動跳線或更改開關(guān)設(shè)置。如果您的設(shè)備位于最終用戶可以訪問它們的位置,這可能是一個可行的選擇,因為最終用戶可以在出現(xiàn)故障時選擇恢復(fù)媒體。這可以通過文件或支持人員的指示來完成。
一些系統(tǒng)使用外部硬件來選擇引導(dǎo)加載程序。運行 RTOS 的小型 MCU 可以監(jiān)控適當(dāng)?shù)南到y(tǒng)活動,并在 Linux 系統(tǒng)未運行的情況下選擇備用引導(dǎo)加載程序。使用外部源正確檢測這可能會很棘手,但切換 GPIO 引腳或?qū)懭牍蚕韮?nèi)存的看門狗定時器可能就足夠了。這也是一個更復(fù)雜的設(shè)計,需要根據(jù)您的系統(tǒng)要求進行考慮。請注意,您可能需要考慮對 MCU 固件映像進行 OTA 更新,這是另一個復(fù)雜程度。
選項 4:eMMC 引導(dǎo)分區(qū)
eMMC [6]規(guī)范的 4.3 版需要 2 個單獨的硬件引導(dǎo)分區(qū)。這些分區(qū)通常為每個 4MB,用于存儲引導(dǎo)加載程序。這些分區(qū)在 Linux 用戶空間是可讀寫的,但默認情況下它們是只讀的;通過寫入 /sys 偽文件系統(tǒng)中的文件來啟用讀寫功能:
曼德的方法
利用 eMMC 引導(dǎo)分區(qū),對分區(qū)的更新是原子的,并且獨立于對根文件系統(tǒng)的更新。eMMC 引導(dǎo)分區(qū)之間沒有自動故障轉(zhuǎn)移,因此這并不能減輕由于引導(dǎo)加載程序更新失敗而導(dǎo)致設(shè)備變磚的問題。但是,這確實可以輕松地為引導(dǎo)加載程序提供更新,而無需為根文件系統(tǒng)進行任何特定調(diào)整。
由于在提供引導(dǎo)加載程序更新時存在板卡風(fēng)險和 OTA 更新過程的穩(wěn)健性降低,Mender 不提供開箱即用的引導(dǎo)加載程序更新。正如所討論的,很難以通用的方式進行,并且最終可能會非常特定于應(yīng)用程序和硬件。Mender更新模塊框架允許插件架構(gòu)支持自定義更新類型。Mender 可以使用自定義更新模塊支持任何任意有效負載類型。此插件架構(gòu)允許提供處理特定負載類型的自定義腳本。允許在特定系統(tǒng)中更新引導(dǎo)加載程序可以使用更新模塊來實現(xiàn)。 根據(jù)應(yīng)用程序的需要以及所用硬件的能力,可以使用上述任何一種方法。
包起來
在現(xiàn)場部署的設(shè)備中上傳系統(tǒng)引導(dǎo)加載程序存在許多風(fēng)險。不合時宜的電源故障可能會使設(shè)備在現(xiàn)場陷入困境,從而導(dǎo)致潛在的昂貴的召回過程。但是,不提供引導(dǎo)加載程序更新機制可能會帶來不可接受的風(fēng)險,具體取決于特定應(yīng)用程序的配置文件。我們介紹了許多允許引導(dǎo)加載程序更新的方法,并討論了每種方法的優(yōu)缺點。這有望讓您作為系統(tǒng)設(shè)計人員為您的系統(tǒng)做出適當(dāng)?shù)倪x擇,并幫助您在適當(dāng)了解設(shè)計風(fēng)險的情況下快速進入市場。
審核編輯:郭婷
評論