?

基于數據流分析的Java 空指針引用異常缺陷檢測?

2024-01-23 13:38王國峰唐云善徐立飛
計算機與數字工程 2023年10期
關鍵詞:指針數據流調用

王國峰 唐云善 徐立飛

(1.南瑞集團有限公司(國網電力科學研究院有限公司) 南京 210003)(2.南京南瑞信息通信科技有限公司 南京 210003)

1 引言

源代碼的安全是計算軟件安全的基石,而源代碼的缺陷檢測正是穩固此塊基石的重要方式[1]。據中國國家信息安全漏洞庫統計,由空指針引用異常(Null Pointer Dereference,NPD)造成的安全漏洞引發了許多嚴重的安全問題,諸如系統崩潰、越權操作、拒絕服務和執行惡意代碼等[2~3]。目前對于NPD 漏洞的檢測主要分為動態檢測和靜態檢測兩種方式[4~5]。其中靜態檢測無需運行程序,直接通過語法和詞法等技術手段對編譯后的文件進一步分析,即可找出程序中可能存在的缺陷。這種檢測方式速度快、效率高,廣受業界青睞[6~7]。

在現有的關于NPD 缺陷靜態檢測方法中,Zhang 等[8]通過對缺陷報告的分析,排除一些明顯的誤報,來提升對NPD 缺陷的檢測準確度,但噪聲報告同時也會對優化結果產生二次影響。畢學軍等[9]通過在控制流的基礎上利用變量區間來表示狀態的前提條件,對程序中不可達路徑進行處理,從而達到減少誤報的目的。但該方法未能進一步解決狀態出現ERROR 情況下,導致分支不可達下的缺陷漏報問題。楊睿等[10]基于NPD 缺陷狀態機模型,通過函數摘要的生成傳遞與使用支撐數組空指針故障的全局分析與檢測,從而減少漏報。但其考慮的函數摘要并不完善,對Java代碼中的諸多函數類型如返回值、I/O 操作類型等均未涉及,因此該方法僅適用于數組的NPD檢測上。

針對上述問題,本文提出了一種基于數據流分析的Java空指針引用異常缺陷檢測方法,該方法根據NPD 缺陷模式的缺陷特征,設計了對應的數據流值、格值計算規則和傳遞函數,以此來確保數據流值在程序控制流圖(Control Flow Graph,CFG)上按照設定的傳遞函數進行前向分析,然后遍歷CFG上每個節點的數據流值,找出格值為ERROR 的變量,報出NPD 缺陷故障點。最后,文章通過對比試驗驗證了該方法的有效性及性能效果。

2 空指針引用異常缺陷

2.1 缺陷模式

缺陷模式指一類缺陷產生時程序所呈現的共同的語法或語義特征,描述了程序的一種屬性,滿足該屬性則產生缺陷[11]。NPD 缺陷模式則是描述了被引用的指針指向了無效的內存區域的屬性。當缺陷模式確定后,被用來檢測某一程序是否違反了程序語法或語義規則的屬性,即被稱為該缺陷模式的缺陷特征[12]。NPD 缺陷模式的缺陷特征就是被引用的指針,因此,通過檢測該指針變量是否為空指針,即可判定是否產生NPD缺陷。

2.2 空指針引用異常缺陷實例

Java 語言中沒有指針這個概念,因而Java 中的空指針用空值句柄(Handle)來表征[13]??罩羔樢脛t表明對一個空值句柄的方法、字段或者域的調用,在此調用過程中,編譯器則會拋出Null Pointer Exception錯誤,即空指針引用異常。

結合圖1 的NPD 代碼實例,變量a 和變量c 的初始化均為空值null。若第8 行變量num1 的值大于b.hashCode(),則變量b 加上字符串“world”的值將賦給變量a,此時a 不再是空值null,從而第15 行系統打印函數對a 的調用不會報錯,但若第8 行的if 條件語句的判斷為false,則a 的值依然為null,從而導致第15行出現NPD錯誤。

圖1 NPD缺陷代碼實例

程序第11 行,a 加c 之后的值賦給變量d,由于a和c均為空值null,從而變量d的值也為空值null,這就導致第12行的d.length()調用語句引發對變量d的NPD,以及第14行也同時出現NPD錯誤。

3 空指針引用異常缺陷檢測流程

NPD 缺陷檢測流程如下所示,共分為五個步驟。其中步驟3至步驟5為本文的主要工作。

步驟1:對待分析源碼進行掃描,通過詞法、語法分析構建源碼的抽象語法樹模型;

步驟2:通過抽象語法樹模型將源碼轉化成三地址碼這種代碼的中間表示;

步驟3:通過多次遍歷三地址碼,構建程序CFG,并設計NPD 缺陷模式的數據流值、數據流值的交匯計算規則和數據流的傳遞函數;

步驟4:在CFG 上,根據傳遞函數計算CFG 中每個節點的數據流值,完成數據流前向分析;

步驟5:遍歷CFG 上各節點分析后的數據流值,根據NPD 缺陷模式狀態劃分,找到格值為ERROR的變量,報出NPD缺陷代碼片段。

4 空指針引用異常缺陷檢測算法

4.1 NPD缺陷模式數據流值

NPD缺陷模式數據流值是一個對,由被分析變量及其格值組成的pair<變量名,格值>。根據NPD的缺陷模式,本文設計的格值集合一共有三個定值,即S={NULL,NOTNULL,ERROR}。其中定值NULL表示Java句柄中被分析變量在前趨數據流節點的格值為NULL;定值NOTNULL 表示Java 句柄中被分析變量在前趨數據流節點的格值為NOTNULL;定值ERROR 表示當前Java句柄中被分析變量產生了空指針引用異常缺陷。

圖2 所示格圖的頂元素為格值ERROR,表明所有檢測變量均出現了NPD 缺陷,這個分析結果是安全的但會出現大量誤報;格圖的底元素為格值NOTNULL,表明所有檢測變量均未出現NPD缺陷,這個分析結果是不安全的且會出現大量漏報;其他數據流值則是無序的空值NULL。NPD缺陷檢測的數據流分析屬于may分析,所以只需在格圖上找到最小不動點,即可得到分析的最優結果。

圖2 數據流值格圖

4.2 數據流值交匯計算規則

當程序經過諸如分支判斷語句時,數據流會分成多個分支,進而需要在分支語句結束后對同一變量的格值完成交匯操作,記作Fmeet。數據流值交匯操作時的計算規則如下:

Fmeet(NULL,NULL)=NULL,表示空值與空值交匯后是空值;

Fmeet(NULL,NOTNULL)=NULL,表示空值與非空值交匯的最小上界是空值;

Fmeet(NOTNULL,NOTNULL)=NOTNULL,表示非空值與非空值交匯后是非空值;

Fmeet(ERROR,NULL)=ERROR,表示ERROR與空值交匯的最小上界是ERROR;

Fmeet(ERROR,NOTNULL)=ERROR,表示ERROR與非空值交匯的最小上界是ERROR;

Fmeet(ERROR,ERROR)=ERROR,表示ERROR與ERROR交匯后是ERROR。

4.3 NPD缺陷檢測的數據流前向分析

NPD 缺陷檢測的數據流前向分析主要由三個部分組成:數據流的傳遞、數據流的交匯以及格值的計算。其中數據流動的規則又稱為傳遞函數,它表征在一個分析語句之前和之后的數據流值受該分析語句的語義約束[14]。對于傳遞函數,本文設定的基本塊(Basic Block)中只有一條程序語句,且一條程序語句對應的一條三地址碼語句記作一條Unit,包含多個程序語句的傳遞函數就可以將各個語句對應的傳遞函數組合起來得到。傳遞函數接受的輸入是一個從程序變量到格中抽象值中元素的映射,而函數的返回值也是這樣一個映射[15]。數據流傳遞函數的設計如下:

式(1)中,Unit 表示CFG 中Unit 圖上的一個節點。{(x,LatticeValue)}就是數據流值。對傳遞函數的規則描述如下:

1)如果Unit是一個賦值語句,則會計算賦值語句右側部分的格值,并與賦值語句的左側變量組成計算后的數據流值傳入下一條Unit;

2)如果Unit 是一個調用語句(包括虛擬調用,靜態調用,特殊調用),則會計算調用語句的傳入參數的格值,并與調用主體組成計算后的數據流值傳入下一條Unit。

根據傳遞函數,具體的算法如圖3所示。

圖3 NPD缺陷檢測的數據流傳遞算法

算法1 首先將CFG 上的每個節點流入數據流值(FlowMapIn)和流出數據流值(FlowMapOut)初始為空的哈希集合,將CFG 上的每一條語句(Unit)存到工作表里(WorkList),然后對每一條語句執行前向分析以確定語句中是否存在狀態約束轉換(第1行~23行)。

若當前分析語句是賦值語句,且賦值語句的左側元素是局部變量,算法1 則會調用算法2 獲取當前變量的數據流值,并將計算后的格值傳遞給下一條分析語句的輸入數據流值(第8行~13行)。

若當前分析語句是調用語句,且調用語句的調用主體是局部變量,算法1 則會調用算法2 獲取此變量的數據流值,并將計算后的格值傳遞給下一條分析語句的輸入數據流值(第14行~19行)。

當工作表里的語句全部遍歷完成后算法1 終止,進而得到CFG上的每個節點的格值。

其中格值計算算法如圖4的算法2所示。算法2的輸入為FlowMapIn和StatementValue。

圖4 NPD缺陷檢測的格值計算算法

StatementValue 為待計算語句部分,它可能是賦值語句的右側部分或者調用語句的傳入參數。算法2會根據待計算部分進行分類計算。

若待計算部分是一個整形常量或字符常量則會返回NOTNULL(第15行~20行);

若待計算部分為空或者構建語句,則會返回NULL(第21行~26行);

若待計算部分是一個局部變量,算法2 則會遍歷流入的數據流值,判斷此處的局部變量在先前節點中的格值,若先前的格值是NULL 或者ERROR,那此時對該變量的調用則為NPD 缺陷,從而返回ERROR,若先前的格值是NOTNULL,則返回NOTNULL,其他情況返回NULL(第6行~14行);

若待計算部分為調用表達式,算法2 則會遞歸調用該算法,獲取計算后的格值(第27行~30行);

若待計算部分是一個二元操作表達式,則會先計算二元操作符兩側成分的格值,當兩側成分的格值均為NOTNULL 時,則返回NOTNULL,當兩側成分的格值中有一側是NULL,且不為ERROR 時,則返回NULL,當兩側成分的格值中有一側是ERROR時,則返回ERROR(第31行~39行)。

最后,當工作表里的待計算語句部分全部計算完成后算法2 終止。此外,數據流值交匯計算的算法如圖5的算法3所示。

圖5 NPD缺陷檢測的數據流值交匯計算算法

4.4 實例解析

按照第4 節的數據流分析算法,對圖1 的NPD缺陷代碼實例進行分析,得到圖6所示結果。

圖6 NPD實例數據流分析

其中,虛線指向的是各語句的輸出數據流值。從圖中可以得到OUT[6]的數據流值中變量num1的格值為ERROR,OUT[7]的數據流值中變量$stack1的格值為ERROR,OUT[8]的數據流值中變量$stack2 的格值為ERROR。這就表明圖1 所示的NPD 實例中,第12 行、14 行和15 行出現了NPD 錯誤,這與2.2節的分析結果是完全一致的。

5 試驗結果分析

以本文上述的NPD 缺陷檢測方法實現的檢測工具ASCA-Java進行試驗,對比目前業界主流的開源和商業檢測工具SpotBugs、PMD 和Fortify,分析本文所提方法的有效性和實際性能表現。

5.1 試驗環境及測試數據

試驗環境:JDK 版本為1.8,操作系統為Mac OS 10.14.6,CPU為因特爾-酷睿i7-8559u四核八線程處理器,主頻2.7GHz,內存32G,硬盤容量1T。

測試數據:本實驗以美國國家安全機構(NSA)旗下的軟件安全中心發布的Juliet test suite java 項目開源測試集為檢測對象。

5.2 結果分析

通過表1 可以看出,本文提出的基于數據流分析的NPD 缺陷檢測法能夠有效地檢測出代碼中的NPD缺陷,與以抽象語法樹為分析基礎的檢測工具SpotBugs和PMD相比,本方法具有更高的準確率和更低的誤報率,由于本方法暫不支持過程間的數據流分析,所以漏報率稍高于商業工具Fortify,但檢測效率要高于Fortify和其他兩款開源檢測工具。

表1 NPD缺陷檢測試驗結果對比

6 結語

本文提出了一種基于數據流分析的NPD 缺陷檢測方法,并通過所開發的測試工具進行對比試驗證明了該方法的有效性。在準確率和誤報率上,該方法要優于Java開源檢測工具SpotBugs和PMD,且在對比的三個檢測工具中耗時最短。本文的下一步工作重點是研究基于過程間的數據流分析來進一步降低缺陷檢測的漏報率。

猜你喜歡
指針數據流調用
汽車維修數據流基礎(下)
核電項目物項調用管理的應用研究
LabWindows/CVI下基于ActiveX技術的Excel調用
一種提高TCP與UDP數據流公平性的擁塞控制機制
為什么表的指針都按照順時針方向轉動
基于系統調用的惡意軟件檢測技術研究
基于數據流聚類的多目標跟蹤算法
基于改進Hough變換和BP網絡的指針儀表識別
北醫三院 數據流疏通就診量
ARM Cortex—MO/MO+單片機的指針變量替換方法
91香蕉高清国产线观看免费-97夜夜澡人人爽人人喊a-99久久久无码国产精品9-国产亚洲日韩欧美综合