接續上集的內容,本文將闡述要發揮處理器中各項新功能所須用到的軟體,探討的主題包括記憶體保護以及晶片啟動等。另外,也說明開發者如何讓大多數軟體在不經修改下仍能受益於各項安全服務,善加利用針對ARMv8-M設計的TrustZone所建立之隔離區域。
缺陷例外功能補強 新增SecureFault機制
缺陷例外早已存在於ARMv6-M與ARMv7-M架構的Cortex-M處理器。ARMv8-M架構進一步增強可用的缺陷例外。在ARMv8-M架構中,如果建置了安全例外,在預設模式下,BusFault與HardFault例外就會鎖定安全區域。藉由設定AIRCR裡面一個名為BFHFNMINS(BusFault HardFault NMI Non-secure)的位元就能變更行為。通常只有在程式沒有使用安全區軟體時才會使用這種方法。
在Cortex-M23處理器中,一旦出現安全違規狀況,就會觸發HardFault例外。在Cortex-M33處理器方面,推出一種名為SecureFault(Exception Type 7)的新型可設定缺陷例外。在預設模式下,SecureFault例外是關閉的,若要啟動可設定系統處理器控制與狀態暫存器(SHCSR)的19位元(SECUREFAULTENA)。
|
圖1 非安全軟體中軟體流程範例 |
一旦建置了安全延伸,如果必須從堆疊框架中擷取出堆疊PC,缺陷例外處理器就得進行更新。對於在非安全狀態下執行的軟體,它們不能置於安全堆疊中的堆疊框架,因此必須檢查EXC_RETURN裡的新S位元(圖1)。若例外處理器以安全軟體的模式運行,就必須執行更多作業來辨識正確的堆疊指標,以及偵測堆疊框架是否含有延伸區段(Extended Section)(圖2)。
|
圖2 安全軟體中缺陷處理器的軟體流程範例 |
安全軟體開發強化 韌體工程師大利多
對於大多數使用市售微控制器的軟體開發者而言,應用軟體的開發主要焦點放在非安全區域上。但對許多軟體開發者,包括晶片廠商、原始設備製造商(OEM)或中介軟體廠商的韌體工程師,他們可能必須開發在安全區域內運行的軟體。
支援安全軟體開發的C語言編譯器
為支援在Cortex-M23與Cortex-M33上開發安全軟體,編譯器必須為Cortex-M安全延伸(Cortex-M Security Extension, CMSE)支援各種ACLE功能。ACLE功能定義了許多函式屬性,讓函式能宣告成安全進入點(Entry Points),並讓函式指標能宣告為非安全。ACLE功能並定義了多種固有函式提供指標檢查與處理器狀態存取,以及多種C語言巨集來支援各種CMSE功能。
ACLE屬於開放性規格,並獲得各家編譯器廠商的支持,協助確保程式碼能在各家廠商的平台上任意移植。然而要注意的是,少數CMSE支援功能屬於選項(例如在跨安全區域函式呼叫中使用堆疊來傳遞參數),在不同廠商的解決方案之間進行移植時應先行確認。
在針對安全狀態編譯程式碼時,應使用用來指定編譯作業屬於安全狀態的命令列選項(例如ARM Compiler編譯器中的「--mcmse」);而C/C++程式碼必須加入特定的CMSE表頭檔(#include "arm_cmse.h")。另外,連結器命令列選項或連結器指令檔必須針對安全進入點的分支Veneer指定放置位置;在連結階段,命令列選項則必須指定輸出函式庫的名稱(非安全軟體開發者會用該函式庫檔案來連結其程式映像)。
若使用CMSIS相容的裝置驅動程式來開發安全軟體,可能會發現有一個額外的partition_.h檔案。這個檔案內含啟動函式TZ_SAU_Setup(),該函式用來設定SAU與系統層級控制器(如果有)以便進行記憶體分隔。該函式亦定義哪些中斷為安全/非安全,並定義其他資源是否能從非安全狀態進行存取。此外,該函式可透過重置處理器中的SystemInit()進行呼叫。
建立跨域函式呼叫
CMSE定義兩種重要的新函式屬性,如表1所示。要建立一個能從非安全區域呼叫的安全API,應加入「cmse_nonsecure_entry」屬性,這個屬性會讓工具鏈自動化產生所須的分支旁支(Veneer),並以SG指令來指定有效的進入點。此外,編譯器會自動產生程式碼,確保存放安全資料的暫存器會被宣告,或者在API呼叫之前回復到原始的非安全值(圖3)。
|
圖3 測試安全軟體的軟體開發流程範例 |
對於安全軟體呼叫非安全API,例如當安全中介軟體必須呼叫非安全區域中的硬體驅動程式函式,這種情況就涉及較多的層面。這是因為安全軟體通常是在非安全軟體之前就已研發,而且在編譯時並不知道非安全API的位址。因此,在許多狀況下,非安全程式碼必須呼叫一個安全API來傳遞函式指標,之後才能回呼函式。這個程序如圖4內之程式碼所述。
在呼叫非安全函式時,C語言編譯器會自動產生指令碼,確保所有安全資料(除函式參數外)都已儲存,而且在進行呼叫之前即從暫存器庫區進行宣告,因此安全資料不會暴露在非安全世界。
|
圖4 當安全軟體呼叫非安全函式時軟體互動範例 |
程式碼審慎撰寫 安全考量永遠擺第一
儘管ARMv8-M架構與CMSE功能提供一個紮實的安全基礎,但安全軟體仍必須審慎撰寫以避免任何漏洞。
舉例來說,儘管安全軟體能存取非安全RAM空間,安全軟體仍應僅使用安全記憶體來儲存一般資料(如堆疊、堆積),唯一的例外只有在安全與非安全軟體之間傳遞資訊。
在大多數應用,輸入參數的有效性對許多安全API至關重要。安全API的輸入參數可能必須複製到安全空間,之後才能進行驗證與處理。這是因為非安全記憶體空間內的資料,可能會被非安全的例外事件進行非同步修改。這方面在《ARMv8-M平台的安全軟體指南》文件中有詳細闡述。另外,安全軟體可運用CMSE提供的固有函式來驗證指標。
以下介紹兩類固有函式,包括TT固有函式和指標檢查固有指令。TT固有函式會用一個輸入指標來執行TT指令(表2)。
關於指標檢查固有指令,CMSE定義兩種位址範圍檢查固有指令,如表3所示。
基於一般安全考量,安全API應檢查函式呼叫是否從非安全的無權限程式碼發出。若是如此,指標檢查函式呼叫應指定無特權檢查程序;安全軟體應使用堆疊限制檢查功能來偵測堆疊溢位錯誤;只有含有安全進入點(分支旁支)的記憶體空間,應宣告為非安全可呼叫(NSC)。如此一來,可避免安全程式碼映像中的其他Binary格式資料不經意間成為安全閘道器。
另外,NSC區中任何未使用空間應予以初始化或填滿零值(或填從其他SG指令沒有的值),以避免意外成為安全閘道器;SRAM初始內容無法預測,若有一個SRAM被設定成NSC區域,必須先予以初始化;由於某些編譯工具不支援在堆疊上的安全邊界兩側傳遞參數,因此最好把函式的參數數量設定較小的上限值,以確保程式碼有更好的可移植性。
有些系統允許執行階段(Runtime)記憶體資源或周邊能在安全與非安全區域之間切換。然而,這樣的切換必須審慎為之,以避免安全資訊外洩,以降低遭遇注入程式碼攻擊的風險。當一個周邊元件的安全區域進行切換時,不要忘記確保中斷安全區域也須同步更新。
務必注意,記憶體/周邊資源的安全區域進行動態切換,若除錯工具嘗試存取這些位址,即可能導致除錯工具出現意料之外的行為。若安全軟體有用到浮點運算單元(FPU),浮點運算行程控制暫存器(FPCCR)中的TS位元應設為I。
一般而言,除非沒有用到安全軟體,AIRCR的BFHFNMINS值應為0(預設)。
還必須注意,在安全軟體允許執行任何非安全軟體(包括設定BFHFNMINS)之前,應先行設定特權值組態與安全堆疊限制(若有使用)。這樣可避免在安全區域備便之前,非安全軟體(包括非安全例外處理器)就先嘗試呼叫安全API。
如果沒有用到安全世界,且BFHFNMINS設為1,安全軟體開發者即應考慮關閉所有NSC區域,以避免非安全世界軟體去呼叫安全API。
Cortex-M3/M4舊功能罕用 Cortex-M33停止支援
Cortex-M3與Cortex-M4處理器的一些功能,在Cortex-M33中並沒有支援,其中包括:
移除的原因是位元帶作業需要重新映射位址空間。由於TrustZone安全作業是以位址空間分區為基礎,因此位元帶的位址重映像特性可能導致複雜情況。有些微控制器廠商在其周邊元件中加入位元層級處理功能(例如分隔位元設定與位元清除暫存器)來處理這方面的問題。
Cortex-M3與Cortex-M4處理器中的中斷點單元提供一個唯讀記憶體(ROM)修補(Patching)機制。使用這項功能修補位址時,位址會從CODE區域重新映射到SRAM區域,並可能對TrustZone導致複雜問題。因此ARM移除這項功能。ARMv8-M中設計的新中斷點單元提供更好的中斷點功能,這不僅涵蓋所有位址範圍,還允許所有八個比較器用來檢查指令位址。
VECTRESET位元讓除錯器僅重設處理器,不會影響到系統的其餘部分。在ARMv8-M系統中,除錯器與軟體則應使用SYSRESETREQ(系統重置要求)。
軟體最佳化有譜 Cortex-M23/M33受期待
為支援ARMv8-M,許多編譯器進行更新,除了納入針對Cortex-M23與Cortex-M33處理器的各種最佳化外,還加入CMSE功能。為充分發揮Cortex-M23與Cortex-M33處理器的新功能,現有的程式碼應重新編譯。除錯軟體已進行更新,以滿足各種除錯驗證的要求。許多即時作業系統亦進行更新,藉以發揮架構中的各種新增功能。而為了支援更高階的處理加速,Cortex-M33處理器支援一個協同處理器介面,讓Cortex-M33微控制器廠商在其SoC中加入硬體元件,以加快某些特殊處理作業。
(本文作者為安謀國際處理器事業部資深嵌入式技術經理)