楊 斌,蔣 維,常澤海
(1.西安交通大學(xué)核科學(xué)與技術(shù)學(xué)院,西安 710049;2.中國(guó)核動(dòng)力研究設(shè)計(jì)院核反應(yīng)堆系統(tǒng)設(shè)計(jì)技術(shù)重點(diǎn)實(shí)驗(yàn)室,成都 610213)
隨著核電領(lǐng)域的自動(dòng)化和數(shù)字化發(fā)展,核電儀控軟件在整個(gè)核電系統(tǒng)中扮演的角色越來(lái)越重要,這對(duì)核電儀控軟件提出了更高的安全性和可靠性要求。由于C語(yǔ)言的高性能且能夠直接操作硬件的特性,目前大部分核電儀控軟件采用C語(yǔ)言進(jìn)行開(kāi)發(fā)。然而,C語(yǔ)言的不安全特性使得開(kāi)發(fā)的軟件系統(tǒng)易出現(xiàn)安全性問(wèn)題,核電安全級(jí)儀控軟件開(kāi)發(fā)過(guò)程中必須通過(guò)遵循嚴(yán)格的安全標(biāo)準(zhǔn)規(guī)范以及引入一系列軟件開(kāi)發(fā)活動(dòng)以規(guī)避C語(yǔ)言的安全風(fēng)險(xiǎn)。目前常用的標(biāo)準(zhǔn)有:MSRA-2004、GJB-5369-2005《航天型號(hào)軟件C語(yǔ)言安全子集》、GB/T28169-2011《嵌入式軟件C語(yǔ)言編碼規(guī)范》[1]等,軟件開(kāi)發(fā)活動(dòng)包括軟件代碼靜態(tài)分析、軟件測(cè)試和軟件V&V活動(dòng)[2]。一方面,檢測(cè)工具的檢測(cè)能力和準(zhǔn)確性直接影響檢測(cè)結(jié)果,代碼檢測(cè)工具存在誤報(bào)或漏檢的可能;另一方面,無(wú)論是軟件測(cè)試還是軟件V&V,均無(wú)法保證百分之百的覆蓋率。因此,引入標(biāo)準(zhǔn)規(guī)范和軟件開(kāi)發(fā)活動(dòng)屬于被動(dòng)防御手段,并不能完全規(guī)避C語(yǔ)言的不安全特性帶來(lái)的安全風(fēng)險(xiǎn)。
Rust語(yǔ)言自問(wèn)世以來(lái),致力于成為優(yōu)雅解決高并發(fā)、高安全系統(tǒng)問(wèn)題的編程語(yǔ)言,適用于大型場(chǎng)景,創(chuàng)造維護(hù)能夠保持大型系統(tǒng)完整的邊界,因此更加強(qiáng)調(diào)安全性、內(nèi)存布局控制和并發(fā)處理方面的特性,在網(wǎng)絡(luò)服務(wù)器領(lǐng)域引起極大重視。核電領(lǐng)域因其特殊性,Rust語(yǔ)言應(yīng)用尚處于探索階段。本文就Rust語(yǔ)言應(yīng)用于核電安全級(jí)儀控軟件開(kāi)發(fā),以規(guī)避C語(yǔ)言的安全風(fēng)險(xiǎn)的可能性進(jìn)行探討。
C語(yǔ)言是一種不安全的語(yǔ)言,其固有特性易使得所開(kāi)發(fā)的程序存在安全缺陷,同時(shí)其極大的靈活性也容易導(dǎo)致開(kāi)發(fā)人員的不安全使用行為,均為軟件帶來(lái)了安全隱患,可能導(dǎo)致軟件失效。
在C語(yǔ)言中未對(duì)指針的使用加以限制,指針理論上可以訪(fǎng)問(wèn)任意的內(nèi)存空間。若訪(fǎng)問(wèn)了非法或者受保護(hù)的內(nèi)存地址,則會(huì)導(dǎo)致內(nèi)存問(wèn)題,然而C語(yǔ)言編譯器并未對(duì)指針操作進(jìn)行嚴(yán)格的安全性檢查。這帶來(lái)了如下幾方面的問(wèn)題:
1)C語(yǔ)言不對(duì)空指針進(jìn)行檢查,空指針?biāo)赶虻膬?nèi)存空間一般是受保護(hù)的。在軟件中對(duì)空指針進(jìn)行解引用,會(huì)引發(fā)軟件異常。
2)C語(yǔ)言中不強(qiáng)制要求指針初始化,未初始化的指針即是野指針。野指針的值取決于以前遺留的是什么值,因此它可能指向未知的內(nèi)存空間,對(duì)野指針進(jìn)行解引用,可能會(huì)引發(fā)軟件異常,也可能不會(huì)。但無(wú)論如何,這個(gè)行為不屬于預(yù)期內(nèi)的安全行為,存在安全隱患。
3)C語(yǔ)言使用指針訪(fǎng)問(wèn)動(dòng)態(tài)申請(qǐng)的內(nèi)存空間,當(dāng)內(nèi)存空間使用完畢并進(jìn)行釋放后,指針仍舊指向已釋放的空間,此時(shí)的指針便是懸空指針。它與野指針類(lèi)似,同樣會(huì)操作不屬于自己的內(nèi)存空間,導(dǎo)致安全問(wèn)題。圖1展示了對(duì)懸空指針進(jìn)行操作的情況。
C語(yǔ)言?xún)?nèi)存管理由開(kāi)發(fā)人員通過(guò)內(nèi)存管理函數(shù)手動(dòng)進(jìn)行分配和釋放,C語(yǔ)言提供了一系列的內(nèi)存管理函數(shù)(如malloc、calloc、recalloc、free等)。若使用不當(dāng),會(huì)引發(fā)內(nèi)存問(wèn)題。然而,C編譯器在編譯階段并不能暴露此種情況,導(dǎo)致運(yùn)行過(guò)程中出現(xiàn)內(nèi)存錯(cuò)誤,可能引發(fā)軟件崩潰。
常見(jiàn)的內(nèi)存問(wèn)題有內(nèi)存泄漏和內(nèi)存釋放錯(cuò)誤。動(dòng)態(tài)申請(qǐng)的內(nèi)存使用完畢后,并未調(diào)用相應(yīng)的釋放函數(shù)對(duì)其進(jìn)行釋放,則會(huì)造成內(nèi)存泄漏[3]。C語(yǔ)言無(wú)法暴露內(nèi)存泄漏問(wèn)題,內(nèi)存泄漏導(dǎo)致可用的內(nèi)存越來(lái)越少,最終引發(fā)程序崩潰,圖2對(duì)此種情況進(jìn)行了展示。內(nèi)存的分配和釋放要配對(duì),若對(duì)一塊內(nèi)存空間執(zhí)行重復(fù)釋放,也會(huì)造成內(nèi)存釋放錯(cuò)誤。若指針指向的地址并不是內(nèi)存分配后的地址,對(duì)其執(zhí)行釋放操作,也是危險(xiǎn)的。

圖2 內(nèi)存泄漏Fig.2 Memory leak
2004年以來(lái),微軟安全響應(yīng)中心(MSRC)已對(duì)所有報(bào)告過(guò)的微軟安全漏洞進(jìn)行了分類(lèi)。根據(jù)他們提供的數(shù)據(jù),所有微軟每年的補(bǔ)丁中約有70%是針對(duì)內(nèi)存安全漏洞的修復(fù)程序,故而微軟正在考慮使用新的內(nèi)存安全語(yǔ)言替代C/C++語(yǔ)言進(jìn)行操作系統(tǒng)的開(kāi)發(fā)。
Rust語(yǔ)言是Mozilla主導(dǎo)開(kāi)發(fā)的通用、編譯型語(yǔ)言,專(zhuān)注于安全,尤其是并發(fā)安全[4]。設(shè)計(jì)準(zhǔn)則為“安全、并發(fā)、實(shí)用”,支持函數(shù)式、并發(fā)式、過(guò)程式以及面向?qū)ο蟮木幊田L(fēng)格。在語(yǔ)法上和C++類(lèi)似,但是在設(shè)計(jì)上保證性能的同時(shí)需提供更好的內(nèi)存安全,通過(guò)一系列的手段讓不安全的內(nèi)存風(fēng)險(xiǎn)在編譯階段暴露,保證了程序運(yùn)行中的內(nèi)存安全。
每種編程語(yǔ)言都有其管理使用計(jì)算機(jī)內(nèi)存的方式,要么通過(guò)開(kāi)發(fā)人員手動(dòng)進(jìn)行內(nèi)存的分配和釋放(如C語(yǔ)言),要么提供垃圾回收機(jī)制,在程序運(yùn)行時(shí)不斷尋找不再被使用的內(nèi)存并進(jìn)行釋放(如Java語(yǔ)言)。前者將內(nèi)存管理權(quán)交給了開(kāi)發(fā)人員,存在人因的內(nèi)存安全風(fēng)險(xiǎn),后者會(huì)降低程序運(yùn)行時(shí)性能。而Rust語(yǔ)言采用了一種全新的方式:通過(guò)所有權(quán)系統(tǒng)管理內(nèi)存。Rust語(yǔ)言編譯器在編譯期間執(zhí)行所有權(quán)規(guī)則檢查,即可明確所有對(duì)象的作用域和生命周期,從而可以在某個(gè)對(duì)象不再被使用時(shí)將其銷(xiāo)毀,并且不影響程序運(yùn)行時(shí)性能。
Rust語(yǔ)言的所有權(quán)系統(tǒng)規(guī)定了下述的所有權(quán)規(guī)則:
1)Rust語(yǔ)言中每個(gè)對(duì)象都有一個(gè)所有者。
2)對(duì)象有且只有一個(gè)所有者。
3)所有者離開(kāi)作用域后,其所代表的對(duì)象會(huì)被立即銷(xiāo)毀。
4)賦值語(yǔ)句、函數(shù)調(diào)用等會(huì)導(dǎo)致所有權(quán)轉(zhuǎn)移,原有所有者失去對(duì)象的所有權(quán)。
Rust語(yǔ)言的所有權(quán)系統(tǒng)保證了某一時(shí)刻只有一個(gè)變量持有對(duì)象的所有權(quán),避免了數(shù)據(jù)競(jìng)爭(zhēng)和重復(fù)釋放。所有者離開(kāi)作用域時(shí)銷(xiāo)毀其對(duì)象的機(jī)制,也防止了內(nèi)存泄露。
在Rust語(yǔ)言的所有權(quán)規(guī)則中,當(dāng)某個(gè)變量被傳入一個(gè)新的作用域中時(shí),變量的所有權(quán)也從原作用域轉(zhuǎn)移到新的作用域;當(dāng)變量返回原作用域時(shí),卻已經(jīng)喪失了原有的所有權(quán)。一個(gè)典型的例子是:某個(gè)變量作為參數(shù)傳入函數(shù),執(zhí)行函數(shù)調(diào)用后,該變量會(huì)失去對(duì)象的所有權(quán),后續(xù)無(wú)法通過(guò)該變量使用其對(duì)象,這并不符合預(yù)期。因此,Rust語(yǔ)言提供了所有權(quán)借用特性,非所有者的變量或者函數(shù)想要訪(fǎng)問(wèn)對(duì)象時(shí),通過(guò)借用對(duì)象所有者的所有權(quán)以達(dá)到目的,所有權(quán)借用不造成所有權(quán)轉(zhuǎn)移,借用完畢后歸還所有權(quán)。借用所有權(quán)會(huì)讓所有者受如下限制:
1)在不可變借用期間,所有者不能修改資源,并且也不能再進(jìn)行可變借用。
2)在可變借用期間,所有者不能訪(fǎng)問(wèn)資源,并且也不能再出借所有權(quán)。
Rust語(yǔ)言對(duì)指針的使用進(jìn)行了限制,原生指針(類(lèi)似C語(yǔ)言的指針)只能在不安全代碼中進(jìn)行使用,針對(duì)安全編程,Rust語(yǔ)言提供了一種更高級(jí)的指針語(yǔ)義——引用。引用與指針的差別在于:指針保存某塊內(nèi)存的地址,引用則可看作某塊內(nèi)存的別名,引用的使用要求滿(mǎn)足Rust語(yǔ)言編譯器各種安全檢查規(guī)則。
在Rust語(yǔ)言的所有權(quán)系統(tǒng)中,引用產(chǎn)生所有權(quán)的借用,引用在離開(kāi)作用域時(shí)歸還借用的所有權(quán)。雖然使用引用與直接使用被引用者一樣自然,但是受如下規(guī)則的限制,違反規(guī)則中的任何一條,編譯器便會(huì)報(bào)錯(cuò)并給出提示。
1)在某個(gè)時(shí)刻,某個(gè)變量要么擁有一個(gè)可變引用,要么擁有多個(gè)不可變引用。
2)引用必須保證有效。
3)引用的生命周期不能超過(guò)被引用者的生命周期。
引用避免了空指針和野指針的情況,防止了數(shù)據(jù)競(jìng)爭(zhēng)。引用的生命周期檢查保證了數(shù)據(jù)不會(huì)在其引用離開(kāi)其作用域之前被釋放而變成懸垂?fàn)顟B(tài),避免了C語(yǔ)言中懸空指針的問(wèn)題。
Rust語(yǔ)言?xún)?yōu)于C語(yǔ)言的安全特性,不輸于C語(yǔ)言的性能,以及具備嵌入式開(kāi)發(fā)的能力,使其十分適合用于執(zhí)行開(kāi)發(fā)安全功能的嵌入式軟件,結(jié)合核電儀控軟件安全可靠的發(fā)展需求,使得Rust語(yǔ)言在核電儀控領(lǐng)域的應(yīng)用成為可能。
目前在核電儀控領(lǐng)域,核電儀控軟件為了滿(mǎn)足功能安全中的確定性要求,大多采用定周期的裸機(jī)系統(tǒng)。隨著核電儀控系統(tǒng)自動(dòng)化、智能化發(fā)展,核電儀控軟件功能日益增多,裸機(jī)系統(tǒng)的弊端也逐漸凸顯出來(lái)。
1)傳統(tǒng)的裸機(jī)系統(tǒng)按照順序執(zhí)行各功能,隨著軟件功能的增多,軟件周期增大,導(dǎo)致安全相關(guān)的功能不能及時(shí)執(zhí)行,無(wú)法滿(mǎn)足安全功能的實(shí)時(shí)性要求。
2)裸機(jī)系統(tǒng)各功能模塊存在耦合,系統(tǒng)功能的增多導(dǎo)致軟件復(fù)雜性變高,可維護(hù)性變差。盡管采用安全級(jí)操作系統(tǒng)可避免裸機(jī)系統(tǒng)帶來(lái)的問(wèn)題,然而使用不安全的C語(yǔ)言開(kāi)發(fā)一款安全級(jí)操作系統(tǒng)無(wú)疑是一項(xiàng)成本極高且難度極大的任務(wù),而且C語(yǔ)言的不安全特性也導(dǎo)致其開(kāi)發(fā)的操作系統(tǒng)的安全性受到質(zhì)疑。因此,時(shí)至今日,在功能安全相關(guān)的核電儀控軟件中幾乎未見(jiàn)到操作系統(tǒng)的身影。
Rust語(yǔ)言的出現(xiàn)可能改變這一現(xiàn)狀。一方面,Rust語(yǔ)言具有豐富的高級(jí)語(yǔ)言特性,如函數(shù)式編程語(yǔ)言的模式匹配和類(lèi)型推導(dǎo),基于trait的泛型機(jī)制,強(qiáng)大的抽象能力等,非常適合大型系統(tǒng)編程場(chǎng)景,采用Rust語(yǔ)言開(kāi)發(fā)操作系統(tǒng)變得相對(duì)簡(jiǎn)單;另一方面,Rust語(yǔ)言提供強(qiáng)大的類(lèi)型系統(tǒng)和獨(dú)特的生命周期管理,實(shí)現(xiàn)了編譯內(nèi)存管理,保證內(nèi)存安全和線(xiàn)程安全的同時(shí),運(yùn)行效率還能與C/C++保持在同一級(jí)別。
基于Rust語(yǔ)言開(kāi)發(fā)的安全級(jí)操作系統(tǒng),在成本、安全、效率等方面存在較大優(yōu)勢(shì)和競(jìng)爭(zhēng)力,未來(lái)應(yīng)用于核電儀控軟件領(lǐng)域的可能性較大。一個(gè)典型的基于Rust語(yǔ)言的安全級(jí)操作系統(tǒng)如圖3所示。

圖3 Rust語(yǔ)言安全級(jí)操作系統(tǒng)架構(gòu)Fig.3 Rust language security level operating system architecture
裸機(jī)系統(tǒng)中沒(méi)有嚴(yán)格對(duì)應(yīng)用程序和設(shè)備驅(qū)動(dòng)程序進(jìn)行隔離,整個(gè)系統(tǒng)核心由一個(gè)大的死循環(huán)構(gòu)成,系統(tǒng)所有功能模塊均包含在死循環(huán)內(nèi),應(yīng)用程序和設(shè)備驅(qū)動(dòng)程序之間存在直接或間接的功能耦合,難以實(shí)現(xiàn)獨(dú)立安全的應(yīng)用程序。
基于Rust語(yǔ)言開(kāi)發(fā)的操作系統(tǒng),使用Rust語(yǔ)言開(kāi)發(fā)安全級(jí)應(yīng)用程序變得簡(jiǎn)單。安全級(jí)操作系統(tǒng)實(shí)現(xiàn)了應(yīng)用與驅(qū)動(dòng)程序、應(yīng)用程序與應(yīng)用程序之間的安全隔離,保證了單個(gè)應(yīng)用程序的安全性、獨(dú)立性,也避免了單個(gè)應(yīng)用程序故障導(dǎo)致系統(tǒng)失效的風(fēng)險(xiǎn)。
Rust語(yǔ)言作為一門(mén)新的編程語(yǔ)言,目前在核電領(lǐng)域的應(yīng)用幾乎處于空白,沒(méi)有成熟的項(xiàng)目和成功的經(jīng)驗(yàn)作為參考和支撐,不免令人對(duì)其應(yīng)用于核電儀控領(lǐng)域的安全性、適用性和可靠性產(chǎn)生擔(dān)憂(yōu)。
C語(yǔ)言在核電領(lǐng)域的廣泛應(yīng)用,配套的相關(guān)行業(yè)標(biāo)準(zhǔn)十分完善。IEC61508-7[5]的附錄C4.5中對(duì)C語(yǔ)言用于開(kāi)發(fā)功能安全系統(tǒng)給出了限定條件:“具有子集和編碼標(biāo)準(zhǔn)和靜態(tài)分析工具的C”。為了滿(mǎn)足此條件,制定了MISRA-2004、GJB5369-2005《航天型號(hào)軟件C語(yǔ)言安全子集》、GB/T28169-2011《嵌入式軟件C語(yǔ)言編碼規(guī)范》等一系列C語(yǔ)言相關(guān)標(biāo)準(zhǔn)和規(guī)范。
而Rust語(yǔ)言目前暫未納入IEC61508推薦用于開(kāi)發(fā)功能安全系統(tǒng)的系列編程語(yǔ)言中,因此相關(guān)的行業(yè)標(biāo)準(zhǔn)缺失,缺少相關(guān)標(biāo)準(zhǔn)進(jìn)行指導(dǎo)和規(guī)約,其應(yīng)用與核電儀控領(lǐng)域的競(jìng)爭(zhēng)力被削弱。
Rust語(yǔ)言目前僅具備基礎(chǔ)的編譯、調(diào)試等生產(chǎn)工具,尚未提供用于功能安全開(kāi)發(fā)活動(dòng)的工具支持,如經(jīng)過(guò)安全認(rèn)證的開(kāi)發(fā)工具、驗(yàn)證軟件、靜態(tài)解析和自動(dòng)化測(cè)試工具等,作為功能安全領(lǐng)域軟件開(kāi)發(fā)活動(dòng)必需的生產(chǎn)工具,其重要性不言而喻,使用未經(jīng)認(rèn)證的開(kāi)發(fā)工具所開(kāi)發(fā)的軟件不能滿(mǎn)足安全要求。因此,要使得Rust語(yǔ)言廣泛應(yīng)用于核電儀控領(lǐng)域,完善安全相關(guān)的開(kāi)發(fā)工具是前提。
目前大部分的核電儀控軟件開(kāi)發(fā)采用C語(yǔ)言,熟悉Rust語(yǔ)言的開(kāi)發(fā)人員較少,Rust語(yǔ)言應(yīng)用于核電儀控領(lǐng)域,需要開(kāi)發(fā)人員由C語(yǔ)言遷移到Rust語(yǔ)言,遷移存在幾個(gè)難點(diǎn):一是開(kāi)發(fā)人員缺少Rust語(yǔ)言的開(kāi)發(fā)經(jīng)驗(yàn),需要從頭學(xué)起;二是Rust語(yǔ)言和C語(yǔ)言的語(yǔ)言特性差異較大,因此在軟件設(shè)計(jì)和軟件編碼上均存在較大差異,開(kāi)發(fā)人員需要編程思維的轉(zhuǎn)變;三是Rust語(yǔ)言在市場(chǎng)應(yīng)用方面還比較小眾,可用的功能函數(shù)庫(kù)及開(kāi)源庫(kù)較少,需要開(kāi)發(fā)人員自己造輪子,對(duì)開(kāi)發(fā)人員提出了更高的要求。
Rust語(yǔ)言的特性與核電儀控軟件發(fā)展需求完美契合,本文對(duì)Rust語(yǔ)言在核電儀控軟件的應(yīng)用可能性進(jìn)行了探討,旨在推動(dòng)Rust語(yǔ)言在核電儀控領(lǐng)域的應(yīng)用發(fā)展。可以預(yù)見(jiàn),隨著Rust語(yǔ)言自身的發(fā)展,相關(guān)標(biāo)準(zhǔn)的出臺(tái)以及配套工具的完善,各類(lèi)相關(guān)機(jī)構(gòu)和組織都將對(duì)Rust語(yǔ)言在核電儀控領(lǐng)域的應(yīng)用進(jìn)行積極的探索和研究,Rust語(yǔ)言會(huì)在核電儀控領(lǐng)域展現(xiàn)出強(qiáng)大的活力。