引言
隨著嵌入式計算設備基礎硬件性能的提升,在通信、工業(yè)制造、交通運輸?shù)阮I域,嵌入式系統(tǒng)逐漸承擔起更加綜合化和關鍵的任務,這也導致嵌入式軟件在結構愈加復雜的同時,其安全性問題也越來越受到重視。堆棧是嵌入式軟件中的重要存儲結構,它用于保存軟件運行過程中的關鍵信息。堆棧的安全也直接影響到嵌入式軟件的安全,因此,在一些安全性要求較高的領域,堆棧的使用分析已成為保證軟件安全性的必要工作之一,如機載領域DO—178C中要求,在對軟件源代碼的準確性和一致性評審和分析時需要包含對堆棧使用的分析。本文結合現(xiàn)有技術,說明如何進行嵌入式軟件堆棧使用分析[1]。
1堆棧的概念
堆棧,又稱棧,是一種后進先出的數(shù)據(jù)結構。當軟件中任務因函數(shù)調用、中斷或異常處理而發(fā)生跳轉時,會將任務現(xiàn)場的上下文信息、變量、參數(shù)等緩存到堆棧中,待處理完成后,返回時從堆棧中再恢復現(xiàn)場信息繼續(xù)處理[2]。
堆棧因使用場景不同,通常分為三種:任務棧、任務異常棧和中斷棧。
任務棧是軟件中任務在正常運行時使用到的棧。任務在運行時會持續(xù)進行函數(shù)調用,每一次調用都意味著一次函數(shù)跳轉。任務棧用于在函數(shù)跳轉前緩存現(xiàn)場信息,在函數(shù)返回時從任務棧中恢復現(xiàn)場信息。
任務異常棧是系統(tǒng)處理任務引發(fā)異常時使用到的棧。任務在運行時可能會因為程序錯誤而引起系統(tǒng)異常,此時操作系統(tǒng)會進入異常處理,該處理過程中使用任務異常棧保存異常發(fā)生現(xiàn)場信息和處理過程信息。
中斷棧是系統(tǒng)處理外部中斷時使用到的棧。任務在運行時可能會被外部中斷打斷,此時操作系統(tǒng)會進入中斷處理,該處理過程中使用中斷棧保存中斷發(fā)生現(xiàn)場信息和處理過程信息。
嵌入式軟件的運行實際上是多個任務的持續(xù)調度和執(zhí)行,通常操作系統(tǒng)在創(chuàng)建每個任務時都會為其分配一個任務棧和一個任務異常棧。任務從其入口函數(shù)開始啟動執(zhí)行,執(zhí)行過程中發(fā)生函數(shù)調用時進行數(shù)據(jù)壓棧,用任務棧存儲參數(shù)、變量、寄存器值等臨時數(shù)據(jù)。函數(shù)返回時進行彈棧,從任務棧中恢復臨時數(shù)據(jù)。任務切換時會切換使用的任務棧,因此任務棧之間是相互隔離的。任務運行時可能因代碼缺陷等原因觸發(fā)系統(tǒng)異常,此時停止任務運行,將任務棧切換為任務異常棧進行異常處理,處理完成后再切換回任務棧。任務運行時會被外部設備中斷打斷,如定時器中斷、串口中斷等,此時停止任務運行,將任務棧切換到中斷棧進行中斷處理,處理完成后再切換回任務棧。
2嵌入式軟件堆棧使用分析目的
嵌入式軟件堆棧使用分析的目的是分析并計算軟件運行期間堆棧的最差使用情況,確認堆棧資源分配是否合理'需確保在最差情況下也不會出現(xiàn)棧溢出,從而保證軟件運行過程中堆棧中的關鍵數(shù)據(jù)始終是正確的。
任務棧是軟件運行過程中被操作最頻繁的堆棧,且存儲著任務運行時的關鍵信息。任務棧中的信息若被破壞或篡改'將會導致程序運行不符合預期甚至程序崩潰。對于高安全性的嵌入式軟件'針對任務棧的堆棧使用分析是軟件安全性保證工作的重要部分。故本文只針對嵌入式軟件任務棧的堆棧使用分析方法進行說明。
3嵌入式軟件堆棧使用分析技術
在進行嵌入式軟件堆棧使用分析時可以采用多種技術,以下針對三種常見的技術方法進行說明。
1)手工計算法:人工計算任務執(zhí)行流程中各函數(shù)調用期間所需的任務棧空間大小,并估算出所有可能的調用路徑上所需的任務??臻g大小,其中值最大的即為任務棧的最壞使用情況。該方法需要分析人員熟悉程序源代碼和函數(shù)調用期間使用的寄存器數(shù)量和每個寄存器所占用的??臻g大小。對于較復雜的軟件,該方法工作量大、耗時長、易出錯,其計算結果準確程度依賴于分析人員個人能力。
2)靜態(tài)代碼分析法:通過堆棧分析工具對代碼展開靜態(tài)分析,從而計算出任務棧的最壞使用情況及路徑。工具以任務入口函數(shù)為起點,計算出一條從起點到調用終點的任務棧最壞使用路徑,該路徑上各函數(shù)節(jié)點的堆棧使用之和便是任務棧的最壞使用情況。該方法僅前期準備階段需要一定工作量,后續(xù)階段工作易實施、耗時短、結果直觀。但該方法無法分析動態(tài)調用場景,如通過指針調用,需要人工干預。
3)動態(tài)運行時分析法:通過動態(tài)分析工具監(jiān)控程序的運行時堆棧使用情況從而獲得最壞使用情況。該方法通常需先按照工具約定對代碼進行插樁并重新編譯生成可執(zhí)行程序,之后通過執(zhí)行測試用例覆蓋所有可能的程序路徑,工具可以跟蹤用例執(zhí)行期間的函數(shù)調用和返回,記錄堆棧的使用情況,最終分析出堆棧最壞使用情況。該方法分析階段自動化,無須人工干預、工作量較小、可覆蓋動態(tài)調用場景。但該方法分析結果準確程度依賴于測試用例設計完善程度,若測試用例未覆蓋到全部路徑,則可能會導致結果不準確。
綜上所述,相較于其他兩種方法,靜態(tài)代碼分析法使用工具代替人工分析,效率更高,同時無須部署運行目標軟件,更加方便靈活。因此本文基于靜態(tài)代碼分析法,介紹如何通過靜態(tài)分析工具stackAnalyer進行嵌入式軟件堆棧使用分析。
4 stackAnaIyer概述
stackAnalyer是一款由Abslnt公司開發(fā)的用于嵌入式軟件堆棧使用情況分析的工具。它是一款靜態(tài)分析工具,不依賴程序執(zhí)行。它通過對二進制可執(zhí)行文件展開靜態(tài)分析,自動分析從輸入的程序入口函數(shù)到結束的所有可能調用路徑,并計算路徑上的堆棧使用情況,識別堆棧最差使用情況和路徑。stackAnalyer工具的工作原理如下:
1)以任務入口函數(shù)為起點分析代碼,為任務建立一棵調用樹;
2)分析該調用樹中每個節(jié)點上函數(shù)的堆棧使用量;
3)分析并計算從樹根節(jié)點到葉子節(jié)點哪條調用路徑上經(jīng)過的節(jié)點函數(shù)的堆棧使用量之和最大,該條路徑便是任務堆棧最差使用路徑,使用量之和為任務堆棧最差使用情況。
stackAnalyer工具存在如下兩處功能缺陷:
1)作為靜態(tài)代碼分析工具無法分析包括函數(shù)指針調用在內的動態(tài)調用場景,遇到通過函數(shù)指針的跳轉時,由于跳轉地址不是有效的函數(shù)地址,會導致分析失敗;
2)無法分析系統(tǒng)調用場景,遇到系統(tǒng)調用指令時由于無法識別跳轉目的函數(shù),會終止分析該條路徑。
針對上述兩種場景,在實際操作時需要進行人工干預。
5嵌入式軟件堆棧使用分析方法
本章節(jié)結合stackAnalyer工具分析原理和嵌入式軟件特點,以圖1所示的Taskcase任務為例,針對基于靜態(tài)代碼分析的嵌入式軟件堆棧使用分析實施過程進行說明。
5.1梳理軟件任務信息
在進行堆棧使用分析時,只有明確待分析軟件中運行的任務的基本信息,才能針對具體任務展開分析和評估工作。因此首先需要梳理出軟件系統(tǒng)中運行任務的信息,該工作至關重要,是后續(xù)所有工作的基礎,且只能由人工完成。梳理的任務需要覆蓋本次待分析軟件包含的所有任務,且梳理的信息需準確。梳理的任務信息至少需要包含如下屬性:
1)任務標識:可唯一標識一個任務的屬性,如任務名或任務ID。建議使用任務名作為任務標識,因為通常任務ID在每次運行軟件時都可能不同,而任務名是不變的且易于理解。
2)任務入口函數(shù):創(chuàng)建任務時為其指定的入口函數(shù)。任務入口函數(shù)必須是軟件的可執(zhí)行文件中存在的、有效的函數(shù)符號,若存在同名的函數(shù),則需要說明定義該任務入口函數(shù)的文件名以便區(qū)分。若在創(chuàng)建任務時是通過函數(shù)指針方式指定的入口函數(shù),則需要確定指針具體指向的函數(shù)。只需要記錄函數(shù)名即可,無須關注其參數(shù)和返回值。
3)任務特權狀態(tài):指任務運行時所處的系統(tǒng)特權狀態(tài),如用戶態(tài)和系統(tǒng)態(tài),部分支持虛擬化的系統(tǒng)還存在超級用戶態(tài)等第三種狀態(tài),本文不考慮三態(tài)場景。該屬性說明了任務運行時任務棧所屬的特權空間。
4)分配的任務棧大小:任務創(chuàng)建時為其分配的任務棧大小,用于和分析結果進行對比評估。
5)任務棧最差使用情況:記錄當前任務的堆棧使用分析結果。
6)補充分析說明:若工具分析結果不準確或分析失敗,則需要人工補充分析并說明具體的補充分析情況,否則無須說明。
在實際工作中可以按列表的形式梳理和記錄上述任務信息。以圖1中用戶Taskcase任務為例梳理任務信息表,如表1所示。
5.2工具分析
梳理完成任務信息表后,使用stackAnalyer工具對表中任務記錄逐條進行靜態(tài)代碼分析。工具根據(jù)輸入的任務入口函數(shù)自動分析并生成分析報告,若分析成功,則會在報告中顯示任務棧最大使用大小和路徑。以Taskcase任務為例,分析結果報告如圖2所示。
5.3補充分析
如上文所述,StackAnalyer工具在遇到函數(shù)指針調用和系統(tǒng)調用時會分析失敗,導致無法產(chǎn)生準確的結果,因此需要在工具分析后針對分析失敗的任務進行補充分析。
對于函數(shù)指針調用場景,需要走讀代碼確認程序運行時實際調用的函數(shù),使用工具提供的AIS工程腳本,將該函數(shù)補充到任務的函數(shù)調用樹上,重新分析生成最終結果。若存在多個可能調用的函數(shù),則需要對每一個函數(shù)都進行補充分析,其中結果值最大的即為該任務最終分析結果。
對于系統(tǒng)調用場景,需要根據(jù)具體實現(xiàn)場景分析。系統(tǒng)調用是一種軟中斷,通常作為用戶態(tài)程序進入系統(tǒng)態(tài)的接口。嵌入式操作系統(tǒng)提供兩種通過觸發(fā)系統(tǒng)調用實現(xiàn)函數(shù)調用的機制:
1)進入系統(tǒng)態(tài)的系統(tǒng)調用。該機制是一種跨特權狀態(tài)的調用,會切換任務棧為系統(tǒng)態(tài)堆棧,后續(xù)堆棧的使用不會再影響任務棧,因此無須計算后續(xù)調用函數(shù)的堆棧使用量,將其直接指定為0后重新分析最終結果。
2)共享庫calllib調用。該機制通過觸發(fā)系統(tǒng)調用查找內存空間中共享庫函數(shù)地址從而實現(xiàn)跨層級的函數(shù)調用。該調用只能在同一特權狀態(tài)下進行,不會切換任務棧,后續(xù)堆棧使用會影響當前任務棧,因此需要人工對后續(xù)調用過程進行堆棧使用分析,將結果補充到最終分析結果中。
5.4結果分析
將軟件中所有任務都分析和補充分析完成后,需要逐條對軟件任務信息表中“分配的任務棧大小”和“任務棧最差使用情況”屬性進行比較。若前者不小于后者,則說明該任務的任務棧空間分配充足,不存在棧溢出風險,同時可根據(jù)具體差值適當調整任務棧大小,節(jié)省系統(tǒng)資源;若前者小于后者,則說明存在棧溢出風險,需要擴充該任務的任務??臻g。
6結束語
本文提供了一種基于靜態(tài)代碼分析的嵌入式軟件堆棧使用分析方法,主要說明如何分析軟件任務棧的最差使用情況,同時對指針調用和系統(tǒng)調用兩種特殊調用場景提供了補充分析方法。對于異常棧和中斷棧,其使用場景特殊,無法使用靜態(tài)分析工具自動分析,因此還需進一步研究對其分析的問題和難點。