馬培++翟高壽
摘要:操作系統(tǒng)是整個(gè)計(jì)算機(jī)系統(tǒng)的核心,而設(shè)備驅(qū)動(dòng)程序則占據(jù)操作系統(tǒng)內(nèi)核的相當(dāng)份額并對(duì)系統(tǒng)安全產(chǎn)生舉足輕重的作用。作為主機(jī)與外圍設(shè)備之間通信控制的橋梁,設(shè)備驅(qū)動(dòng)無疑會(huì)受到硬件設(shè)備故障的直接影響。在Linux系統(tǒng)中,驅(qū)動(dòng)程序問題是造成系統(tǒng)安全的主要根源之一。特別地,由于設(shè)備驅(qū)動(dòng)代碼的編寫往往沒有考慮到硬件設(shè)備的瞬時(shí)故障,所以當(dāng)硬件設(shè)備發(fā)生瞬時(shí)差錯(cuò)的時(shí)候,就有可能導(dǎo)致相應(yīng)驅(qū)動(dòng)程序甚至整個(gè)系統(tǒng)出現(xiàn)不可預(yù)料的后果。本文主要討論了面向硬件瞬時(shí)故障的驅(qū)動(dòng)程序敏感代碼的自動(dòng)分析方法,并設(shè)計(jì)和實(shí)現(xiàn)了對(duì)應(yīng)的代碼分析工具原型。運(yùn)用該工具原型對(duì)Linux內(nèi)核設(shè)備驅(qū)動(dòng)源碼的實(shí)驗(yàn)分析結(jié)果表明,該方法和原型可以發(fā)現(xiàn)設(shè)備驅(qū)動(dòng)中潛在的受到硬件設(shè)備瞬時(shí)故障影響的敏感代碼。據(jù)此,采用適當(dāng)方法對(duì)敏感代碼進(jìn)行修復(fù)完善,將可以實(shí)現(xiàn)設(shè)備驅(qū)動(dòng)程序的安全加固。
關(guān)鍵詞:設(shè)備驅(qū)動(dòng)程序;硬件瞬時(shí)故障;敏感代碼;Linux;自動(dòng)分析
中圖分類號(hào):TP311
文獻(xiàn)標(biāo)識(shí)碼:A
DOI:10.3969/j.issn.1003-6970.2015.12.003
本文著錄格式:馬培,翟高壽.面向硬件瞬時(shí)故障的Linux設(shè)備驅(qū)動(dòng)敏感代碼的自動(dòng)分析與檢測[J].軟件,2015,36(12):09-15
0 引言
可靠性對(duì)于操作系統(tǒng)來說一直是最重要的問題,由于計(jì)算機(jī)已經(jīng)深深嵌入到我們的生活中,并且故障一旦發(fā)生我們很難有機(jī)會(huì)能彌補(bǔ),因而我們需要計(jì)算機(jī)更高的可靠性來保證系統(tǒng)運(yùn)行的正確性。
應(yīng)用程序是通過設(shè)備驅(qū)動(dòng)程序喚起設(shè)備,而設(shè)備和驅(qū)動(dòng)程序的交互是通過硬件指定的一個(gè)特定的協(xié)議,如果硬件設(shè)備遵從這些特定的協(xié)議,那么驅(qū)動(dòng)程序就會(huì)完全的信任它并接受來自它的任何輸入。不幸的是設(shè)備常常不能按照這樣的規(guī)章行事,某些故障是由于磨損或者電磁干擾引起的,導(dǎo)致往驅(qū)動(dòng)輸入的數(shù)據(jù)發(fā)生改變,由于驅(qū)動(dòng)在Linux內(nèi)核中,就可能導(dǎo)致不可預(yù)料的系統(tǒng)故障。我們將驅(qū)動(dòng)程序中由于硬件的瞬時(shí)故障而可能導(dǎo)致驅(qū)動(dòng)出現(xiàn)問題的代碼稱為敏感代碼。微軟windows服務(wù)器的研究證明:(l)設(shè)備故障是引起系統(tǒng)崩潰的主要原因;(2)短暫性的硬件設(shè)備故障是正常的現(xiàn)象;(3)驅(qū)動(dòng)程序容忍硬件設(shè)備故障能提高系統(tǒng)的可靠性。沒有解決這些問題,操作系統(tǒng)的可靠性就會(huì)由于設(shè)備及驅(qū)動(dòng)的可靠性而被限制。
針對(duì)設(shè)備瞬時(shí)故障如何自動(dòng)分析和檢測驅(qū)動(dòng)程序的敏感代碼,我們主要是通過驗(yàn)證來自設(shè)備的所有輸入,并且報(bào)告所有存在的故障以使得管理員能夠主動(dòng)管理硬件錯(cuò)誤。本文提出通過代碼分析工具分析設(shè)備驅(qū)動(dòng)程序代碼,找到驅(qū)動(dòng)中使用來自設(shè)備輸入的位置,即敏感代碼在驅(qū)動(dòng)程序中的位置。如果驅(qū)動(dòng)程序使用了沒有通過正確檢查的設(shè)備輸入數(shù)據(jù)并且該數(shù)據(jù)不正確,我們就通過修改驅(qū)動(dòng)程序以插入驗(yàn)證代碼,實(shí)現(xiàn)驅(qū)動(dòng)容忍硬件瞬時(shí)故障的目的。我們實(shí)現(xiàn)了當(dāng)瞬時(shí)故障發(fā)生并導(dǎo)致驅(qū)動(dòng)出現(xiàn)問題的時(shí)候,使用系統(tǒng)日志的方式報(bào)告相關(guān)的硬件故障。為了修復(fù)相應(yīng)的硬件故障所造成的驅(qū)動(dòng)甚至內(nèi)核錯(cuò)誤,我們引入了一個(gè)通用的恢復(fù)服務(wù),這個(gè)服務(wù)可以重置設(shè)備。我們依賴于使用隱匿驅(qū)動(dòng)程序來提供這種修復(fù)的服務(wù),從而能夠針對(duì)設(shè)備故障實(shí)現(xiàn)驅(qū)動(dòng)的恢復(fù)機(jī)制。
本文提出面向硬件瞬時(shí)故障的驅(qū)動(dòng)程序敏感代碼的自動(dòng)分析方法,實(shí)現(xiàn)了自動(dòng)分析工具原型。通過執(zhí)行自動(dòng)分析工具表明,該方法可以準(zhǔn)確檢測到驅(qū)動(dòng)程序中的敏感代碼,并實(shí)現(xiàn)驅(qū)動(dòng)程序的加固,提高驅(qū)動(dòng)及系統(tǒng)的可靠性。
1 硬件瞬時(shí)故障及敏感代碼
1.1 硬件瞬時(shí)故障
現(xiàn)代的CMOS設(shè)備傾向于發(fā)生內(nèi)部錯(cuò)誤,并且在當(dāng)晶體管萎縮的情況下這種錯(cuò)誤會(huì)更加嚴(yán)重。以前的研究表明某些設(shè)備會(huì)發(fā)生短暫的比特位反轉(zhuǎn)錯(cuò)誤,即單個(gè)比特位從1變?yōu)?或從0變成1;永久性的門級(jí)故障,即在一段較長的時(shí)間內(nèi)某一比特保持固定值;橋接故障,即相鄰比特對(duì)發(fā)生電力干擾從而在比特間產(chǎn)生邏輯與門、邏輯或門。環(huán)境條件的改變?nèi)珉姶鸥蓴_或者輻射都能導(dǎo)致產(chǎn)生短暫性故障。設(shè)備的磨損和老化也可能導(dǎo)致門級(jí)故障或者橋接性的錯(cuò)誤。
設(shè)備驅(qū)動(dòng)程序訪問來自設(shè)備的輸入的時(shí)候會(huì)偵查故障,如PCI驅(qū)動(dòng),通過內(nèi)存或I/O端口執(zhí)行I/O操作,設(shè)備驅(qū)動(dòng)可能會(huì)在I/O中讀取到設(shè)備中的錯(cuò)誤的值;如USB驅(qū)動(dòng),使用請(qǐng)求/響應(yīng)協(xié)議,設(shè)備故障可能導(dǎo)致響應(yīng)包中包含錯(cuò)誤的數(shù)據(jù)。很多硬件故障表現(xiàn)為在設(shè)備寄存器中存放了被篡改的值,如設(shè)備控制器內(nèi)部的單比特反轉(zhuǎn)可能傳播到某些內(nèi)部寄存器,而設(shè)備驅(qū)動(dòng)程序讀取到這個(gè)內(nèi)部寄存器中被篡改的值的時(shí)候就可能會(huì)發(fā)生故障。門級(jí)故障也可能存在上述同樣的問題。當(dāng)硬件設(shè)備不能在規(guī)定的時(shí)間內(nèi)響應(yīng),在設(shè)備固件中的錯(cuò)誤表現(xiàn)就可能會(huì)是不正確的輸出數(shù)據(jù)或超時(shí)故障。
1.2 敏感代碼
敏感代碼即驅(qū)動(dòng)程序中由于硬件的瞬時(shí)故障導(dǎo)致驅(qū)動(dòng)出現(xiàn)問題的代碼。各類硬件紛繁復(fù)雜質(zhì)量層次不齊,驅(qū)動(dòng)可能由于物理設(shè)備出現(xiàn)偶發(fā)性的瞬時(shí)故障而影響驅(qū)動(dòng)及系統(tǒng)的安全可靠性。驅(qū)動(dòng)對(duì)外設(shè)的訪問主要是通過I/O端口,I/O端口即外設(shè)寄存器,是接口電路中能被CPU直接訪問的寄存器地址。幾乎每一種外設(shè)都是通過讀寫設(shè)備上的寄存器來進(jìn)行工作的。Linux下訪問I/O端口的方式主要有兩種I/O映射方式和內(nèi)存映射方式。I/O映射方式是直接使用I/O端口操作函數(shù),即使用inb(),outb()等函數(shù)進(jìn)行端口訪問,內(nèi)存訪問方式是將I/O端口映射為內(nèi)存進(jìn)行訪問,即使用I/O內(nèi)存的函數(shù)進(jìn)行端口訪問。當(dāng)發(fā)生硬件瞬時(shí)故障的時(shí)候可能會(huì)篡改I/O端口操作函數(shù)、I/O內(nèi)存函數(shù)的返回值,導(dǎo)致驅(qū)動(dòng)從I/O端口讀取到的數(shù)據(jù)是不正確的值。當(dāng)該數(shù)據(jù)被應(yīng)用到驅(qū)動(dòng)代碼中不恰當(dāng)?shù)奈恢萌缱鳛檠h(huán)條件或數(shù)組下標(biāo)時(shí),就可能導(dǎo)致驅(qū)動(dòng)出現(xiàn)無限輪詢或數(shù)組越界錯(cuò)誤,從而影響驅(qū)動(dòng)運(yùn)行的正確性,降低驅(qū)動(dòng)及系統(tǒng)的可靠性。因此,我們將驅(qū)動(dòng)代碼中使用I/O端口操作函數(shù),并將這些I/O端口函數(shù)直接或間接應(yīng)用在循環(huán)條件或數(shù)組下標(biāo)中的代碼稱之為敏感代碼。
2 設(shè)備驅(qū)動(dòng)敏感代碼自動(dòng)分析方法的設(shè)計(jì)
大部分操作系統(tǒng)供應(yīng)商向設(shè)備驅(qū)動(dòng)程序編寫者提出建議:如何固化驅(qū)動(dòng)程序能夠容忍硬件故障,(1)驗(yàn)證:我們認(rèn)為從設(shè)備中獲取的所有的輸入都是可疑的,都需要進(jìn)行驗(yàn)證才能確保數(shù)據(jù)在正確的范圍內(nèi);(2)超時(shí):當(dāng)設(shè)備一直沒有響應(yīng)的時(shí)候,對(duì)于所有與設(shè)備的交互都應(yīng)當(dāng)有響應(yīng)的措施來應(yīng)對(duì)超時(shí)從而防止永久性的等待;(3)報(bào)告:所有可疑的行為或者操作都需要報(bào)告給操作系統(tǒng)服務(wù)器,從而方便對(duì)硬件故障的集中偵查和管理;(4)恢復(fù):設(shè)備驅(qū)動(dòng)程序應(yīng)當(dāng)能從任何的設(shè)備故障中恢復(fù),如果需要可以通過重置設(shè)備來達(dá)到恢復(fù)的目的。
我們的目標(biāo)主要就是能自動(dòng)完成上述建議??傮w設(shè)計(jì)方案如圖1所示,首先,我們?cè)噲D使得驅(qū)動(dòng)程序能夠容忍設(shè)備故障并能夠從設(shè)備故障中恢復(fù),從而防止了設(shè)備故障導(dǎo)致系統(tǒng)崩潰。我們主要針對(duì)的是短暫性的故障,即當(dāng)重置設(shè)備后這樣的故障不會(huì)再重復(fù)發(fā)生。其次,我們讓設(shè)備驅(qū)動(dòng)程序報(bào)告設(shè)備故障,使得系統(tǒng)管理員能夠知道存在的短暫性故障并及時(shí)的處理故障設(shè)備。自動(dòng)分析方法設(shè)計(jì)的過程主要是(l)分析驅(qū)動(dòng)與設(shè)備交互的原理從而確定I/O端口及I/O內(nèi)存操作函數(shù),(2)分析驅(qū)動(dòng)程序中直接或間接使用I/O端口操作函數(shù)的位置即找到所有受I/O影響的變量,(3)標(biāo)注敏感代碼即被修改的變量被使用在循環(huán)條件或數(shù)組下表的位置。由于短暫性的硬件故障是偶發(fā)性的,我們需要用到簡單的故障注入工具進(jìn)行模擬硬件故障,從而達(dá)到驗(yàn)證實(shí)驗(yàn)的目的。
2.1 110端口及I/O內(nèi)存操作函數(shù)
Linux操作系統(tǒng)內(nèi)核主要有主內(nèi)核、內(nèi)存管理、網(wǎng)絡(luò)、文件系統(tǒng)及其設(shè)備驅(qū)動(dòng)等目錄。其中驅(qū)動(dòng)設(shè)備通常不會(huì)完全集成到內(nèi)核代碼中,且對(duì)應(yīng)于設(shè)備的驅(qū)動(dòng)程序也通常是由第三方編寫實(shí)現(xiàn),因此容易在與內(nèi)核模塊通信、系統(tǒng)調(diào)用等方面產(chǎn)生錯(cuò)誤,從而波及到系統(tǒng)的其他內(nèi)核模塊導(dǎo)致系統(tǒng)崩潰。實(shí)踐證明,在導(dǎo)致系統(tǒng)故障的代碼中,有50%以上的錯(cuò)誤是由設(shè)備驅(qū)動(dòng)程序引起的。
在Linux系統(tǒng)中,主機(jī)與外界交換信息是通過輸入輸出設(shè)備進(jìn)行的,輸入輸出設(shè)備與系統(tǒng)的交互式是使用驅(qū)動(dòng)這個(gè)中間媒介,驅(qū)動(dòng)通過訪問I/O端口實(shí)現(xiàn)與硬件設(shè)備的通信。由于CPU對(duì)外設(shè)端口物理地址的編址有兩種方式:I/O映射方式和內(nèi)存映射方式,所以驅(qū)動(dòng)訪問I/O端口也有兩種途徑:其一為I/O映射方式即是直接使用I/O端口操作函數(shù);其二是內(nèi)存映射方式即將I/O端口映射為內(nèi)存進(jìn)行訪問。這兩種方式都要使用相應(yīng)的I/O端口及I/O內(nèi)存操作函數(shù)對(duì)數(shù)據(jù)進(jìn)行讀寫。I/O端口操作函數(shù)主要包括inb(),inb_p(),insb(),outb(),outb_p()等。I/O內(nèi)存操作函數(shù)主要有ioread8(),ioport_map(),readb(),readl()等。當(dāng)硬件發(fā)生瞬時(shí)故障,可能影響這些函數(shù)的返回值,使得驅(qū)動(dòng)讀取到錯(cuò)誤的值而使驅(qū)動(dòng)出現(xiàn)運(yùn)行錯(cuò)誤,影響驅(qū)動(dòng)甚至系統(tǒng)的可靠性。
2.2 自動(dòng)分析方法
設(shè)備驅(qū)動(dòng)程序依賴于硬件的正確性以確保自身的正確性,我們通過對(duì)驅(qū)動(dòng)程序代碼進(jìn)行靜態(tài)分析找到驅(qū)動(dòng)程序中使用源于設(shè)備的數(shù)據(jù)的位置,并且驗(yàn)證數(shù)據(jù)的有效性,防止在執(zhí)行代碼之前讀取到非有效的數(shù)據(jù)而導(dǎo)致不可預(yù)料的系統(tǒng)錯(cuò)誤。靜態(tài)分析過程的輸入主要是整個(gè)Linux源碼中的驅(qū)動(dòng)代碼,即/Linux/drivers和/Linux/sound下的所有文件,輸出是驅(qū)動(dòng)程序源碼中直接或間接使用I/O和內(nèi)存操作函數(shù)的位置和敏感代碼,即可能潛在的故障源列表。
自動(dòng)分析方法主要是對(duì)系統(tǒng)驅(qū)動(dòng)代碼進(jìn)行掃描,首先針對(duì)驅(qū)動(dòng)的每一個(gè)文件進(jìn)行詞法分析,分析出所有變量、常量、函數(shù)、界符等。然后對(duì)驅(qū)動(dòng)文件進(jìn)行語法分析,找出所有的使用I/O端口操作函數(shù)和I/O內(nèi)存函數(shù)的位置,并標(biāo)注被I/O操作函數(shù)直接或間接修改的變量。最后找出被修改的變量被應(yīng)用在循環(huán)條件或數(shù)組下標(biāo)的位置,即找到驅(qū)動(dòng)中與硬件瞬時(shí)故障相關(guān)的敏感代碼。
針對(duì)自動(dòng)分析結(jié)果所找到的敏感代碼,我們的處理機(jī)制是在敏感代碼處插入超時(shí)、越界檢查和引入自動(dòng)修復(fù)機(jī)制。當(dāng)發(fā)生設(shè)備瞬時(shí)故障并引起驅(qū)動(dòng)程序發(fā)生無限輪詢或數(shù)組越界錯(cuò)誤時(shí),則會(huì)喚起通用的恢復(fù)服務(wù),即隱匿驅(qū)動(dòng)程序,對(duì)設(shè)備進(jìn)行重置,從而達(dá)到恢復(fù)的目的。
3 原型實(shí)現(xiàn)及驗(yàn)證
該原型實(shí)現(xiàn)的開發(fā)平臺(tái)是Ubuntu12.04,在Sourceinsight和Gedit下實(shí)現(xiàn)代碼的編寫,開發(fā)語言為C語言,使用Makefile和gcc4.8.1實(shí)現(xiàn)編譯功能,使用gdb代碼調(diào)試工具對(duì)自動(dòng)分析工具進(jìn)行調(diào)試運(yùn)行。
3.1 原型實(shí)現(xiàn)
本文提出的加固驅(qū)動(dòng)程序主要是排除硬件依賴性故障,固化驅(qū)動(dòng)程序的工作流程如圖2可分為三個(gè)部分,分別為分析驅(qū)動(dòng)源碼找到驅(qū)動(dòng)程序使用源于設(shè)備的數(shù)據(jù)的位置、驗(yàn)證驅(qū)動(dòng)程序獲取硬件數(shù)據(jù)的有效性、插入代碼對(duì)潛在的故障進(jìn)行修復(fù)。找到驅(qū)動(dòng)程序中使用1/0操作函數(shù)的位置主要是對(duì)驅(qū)動(dòng)程序代碼進(jìn)行詞法分析和語法分析用以識(shí)別各種類型的語句,檢測出與硬件通信相關(guān)的I/0操作函數(shù)的使用位置并進(jìn)行標(biāo)注。驗(yàn)證相關(guān)硬件數(shù)據(jù)的有效性是對(duì)從硬件獲取的數(shù)據(jù)進(jìn)行有效性檢查,如:添加計(jì)時(shí)器,檢查數(shù)據(jù)范圍等。插入代碼進(jìn)行修復(fù)是當(dāng)硬件依賴故障偶然性的發(fā)生時(shí)我們插入代碼,引入通用的自動(dòng)修復(fù)機(jī)制,對(duì)硬件進(jìn)行重置從而達(dá)到容忍硬件故障的目的。為實(shí)現(xiàn)對(duì)Linux內(nèi)核源碼中的所有文件應(yīng)用自動(dòng)分析工具,我們通過編寫shell腳本,實(shí)現(xiàn)對(duì)所有驅(qū)動(dòng)文件進(jìn)行遍歷,在遍歷過程中執(zhí)行我們的分析過程。
敏感代碼檢測分析流程如圖3所示。主要有四個(gè)部分組成:驅(qū)動(dòng)程序代碼的預(yù)處理、詞法分析、語法分析、靜態(tài)分析輸出敏感代碼。
3.1.1 設(shè)備驅(qū)動(dòng)源程序的預(yù)處理
預(yù)處理驅(qū)動(dòng)程序是分析代碼的第一步,它主要處理C語言中的各種預(yù)處理語句和注釋。處理的預(yù)處理語句主要包括#define、#error、#include、#if、#else、#ifdef、#line等。同時(shí)在預(yù)處理階段刪除“//”和以“/*”開頭以“*/”結(jié)尾的注釋,以方便后續(xù)代碼分析。
預(yù)處理后生成與分析驅(qū)動(dòng)文件所對(duì)應(yīng)的*.tmp文件。處理后的文件中沒有注釋行,并且完成了宏定義的替換,被include包含的文件也被插入到相應(yīng)的位置。
3.1.2 詞法分析
詞法分析主要是對(duì)經(jīng)過預(yù)處理的程序代碼進(jìn)行分析,得出相關(guān)單詞符號(hào)如關(guān)鍵字(int、struct)、變量、常量(十進(jìn)制、十六進(jìn)制等)、運(yùn)算符(+、-、*、/等)、界符(,、;、(等)等,將這些單詞符號(hào)放入到相應(yīng)的符號(hào)表中。該詞法分析主要檢測的是變量,以方便后續(xù)靜態(tài)分析找到被I/0操作函數(shù)影響的變量。
經(jīng)過詞法分析將相關(guān)的單詞符號(hào)填入到符號(hào)表中,用于記錄源程序中各種單詞符號(hào)的屬性和特征。本文變量和函數(shù)的符號(hào)表的定義如下:
(l)變量標(biāo)識(shí)符的符號(hào)表否為I/O操作函數(shù)*/
}FuncTable:
3.1.3 語法分析
語法分析主要是在完成詞法分析的基礎(chǔ)上對(duì)代碼進(jìn)行語法結(jié)構(gòu)的分析。該分析過程用于獲取與變量和函數(shù)相關(guān)的信息存入到符號(hào)表中,為后續(xù)的靜態(tài)分析做準(zhǔn)備。
(l)提取變量相關(guān)信息,將驅(qū)動(dòng)代碼中出現(xiàn)的每一個(gè)變量的行號(hào)都記錄下來,存放在變量符號(hào)表的定義變量和使用變量的字段中。
(2)提取函數(shù)相關(guān)信息,標(biāo)識(shí)每個(gè)函數(shù)所定義和使用的變量,并記錄下函數(shù)體內(nèi)所引用的函數(shù)名等。
3.1.4 敏感代碼的檢測
通過上述的分析過程,我們能準(zhǔn)確的標(biāo)識(shí)出驅(qū)動(dòng)源碼中所有的標(biāo)識(shí)符及其引用流程,我們靜態(tài)分析的過程包括兩步,第一步是標(biāo)識(shí)出驅(qū)動(dòng)程序中直接或間接使用I/0端口函數(shù)和I/0內(nèi)存函數(shù)的位置,并找到被這些函數(shù)修改的變量標(biāo)注在變量符號(hào)表的tainted字段中。第二步是找出被修改的變量或I/0操作函數(shù)應(yīng)用在循環(huán)條件和數(shù)組下標(biāo)的行號(hào),將其標(biāo)注為敏感代碼輸出到Taintedfor.txt中。
當(dāng)被修改的變量被應(yīng)用在驅(qū)動(dòng)程序的循環(huán)條件中,而由于偶發(fā)性的硬件故障而導(dǎo)致該變量從硬件讀取來的數(shù)據(jù)不是預(yù)期的值,那就可能導(dǎo)致驅(qū)動(dòng)進(jìn)去死循環(huán)永遠(yuǎn)都不能跳出來。由于驅(qū)動(dòng)和系統(tǒng)內(nèi)核有著千絲萬縷的聯(lián)系,驅(qū)動(dòng)的無限輪詢就可能導(dǎo)致不可預(yù)料的系統(tǒng)故障。當(dāng)被修改的變量被應(yīng)用在全局或局部數(shù)組變量的下標(biāo)中,由于數(shù)組下標(biāo)有范圍界限,若因?yàn)榕及l(fā)性的硬件故障而導(dǎo)致從硬件獲取的數(shù)據(jù)值不在該數(shù)組的合法范圍內(nèi),驅(qū)動(dòng)就會(huì)因?yàn)榇嬖谠浇珏e(cuò)誤而導(dǎo)致系統(tǒng)問題。
3.1.5 敏感代碼的修復(fù)與報(bào)告
針對(duì)上述分析出的潛在的故障因素,我們需要對(duì)其進(jìn)行修復(fù)。對(duì)于無限輪詢故障,主要是在驅(qū)動(dòng)中插入代碼打破無限輪詢的條件?;诙啻螌?duì)驅(qū)動(dòng)代碼的延時(shí)測試和其他設(shè)備所使用的延時(shí),我們使用最大的延時(shí)。我們?cè)谘h(huán)內(nèi)添加計(jì)時(shí)器,并設(shè)置最大延時(shí)時(shí)間。當(dāng)在循環(huán)體內(nèi)循環(huán)的時(shí)間超過我們?cè)O(shè)置的最大延時(shí)時(shí)間時(shí),我們就認(rèn)為該循環(huán)陷入了無限輪詢,此時(shí)我們引入通用的恢復(fù)服務(wù)隱匿驅(qū)動(dòng)程序?qū)τ布M(jìn)行重置,重新獲取硬件相關(guān)的信息。對(duì)于數(shù)組越界問題,我們主要是根據(jù)驅(qū)動(dòng)代碼上下文,在被修改變量用在數(shù)組下標(biāo)之前的位置處對(duì)該變量進(jìn)行條件判斷,若變量值在數(shù)組范圍外,則引入通用的恢復(fù)服務(wù),對(duì)故障進(jìn)行恢復(fù)。
在對(duì)無限輪詢和數(shù)組越界的驅(qū)動(dòng)錯(cuò)誤進(jìn)行修復(fù)后,當(dāng)確實(shí)出現(xiàn)硬件故障的時(shí)候我們使用printk函數(shù)實(shí)現(xiàn)系統(tǒng)日志通知系統(tǒng)管理員發(fā)生了硬件故障,以便于系統(tǒng)管理員對(duì)故障進(jìn)行管理和維護(hù)。
3.2 實(shí)驗(yàn)驗(yàn)證
3.2.1 敏感代碼自動(dòng)檢測結(jié)果分析
我們靜態(tài)分析的對(duì)象主要是整個(gè)Linux內(nèi)核驅(qū)動(dòng),內(nèi)核版本為Linux2.6.18。通過分析drivers和sound目錄下的6000多個(gè)源程序文件,這些文件包括的驅(qū)動(dòng)類主要有網(wǎng)卡驅(qū)動(dòng)、聲卡驅(qū)動(dòng)、視頻驅(qū)動(dòng)、SCSI驅(qū)動(dòng)和其它類驅(qū)動(dòng),從靜態(tài)分析的輸出文件中發(fā)現(xiàn)了大量的潛在的無限輪詢和數(shù)組越界錯(cuò)誤。分析結(jié)果表明驅(qū)動(dòng)的硬件依賴性故障是普遍存在的,只有盡量避免這些潛在的錯(cuò)誤才能提高操作系統(tǒng)的可靠性。
使用隨機(jī)抽樣方法檢查驅(qū)動(dòng)代碼分析結(jié)果表明:誤報(bào)率低于9%。對(duì)于無限輪詢錯(cuò)誤,我們檢查了100個(gè)例子,只是發(fā)現(xiàn)了10個(gè)誤報(bào),誤報(bào)原因主要是該驅(qū)動(dòng)自身已經(jīng)實(shí)現(xiàn)了檢查和修復(fù)方法,但這種誤報(bào)并不會(huì)對(duì)驅(qū)動(dòng)造成損害,唯一可能的損害就是增加了少量的不必要的開銷。
3.2.2 敏感代碼修復(fù)與故障報(bào)告
通過使用自動(dòng)分析工具對(duì)驅(qū)動(dòng)源碼進(jìn)行分析,我們能得到所有驅(qū)動(dòng)類中潛在的硬件依賴性故障。由于對(duì)驅(qū)動(dòng)進(jìn)行測試依賴于硬件,我們不可能擁有內(nèi)核驅(qū)動(dòng)所對(duì)應(yīng)的所有的硬件,所以我們主要對(duì)已經(jīng)存在的硬件進(jìn)行驗(yàn)證,如電腦本機(jī)的網(wǎng)卡和聲卡。由于短暫性的硬件故障是偶發(fā)性的,我們無法預(yù)期什么時(shí)候會(huì)發(fā)生,所以我們引入了故障注入工具,模擬硬件故障的發(fā)生。通過故障注入工具模擬硬件故障,我們測試了固化前的驅(qū)動(dòng)和固化后的本機(jī)網(wǎng)卡驅(qū)動(dòng)。在測試過程中,我們發(fā)現(xiàn)對(duì)于固化后的驅(qū)動(dòng)代碼示例如下圖4所示,當(dāng)發(fā)生了硬件瞬時(shí)故障的時(shí)候能夠喚起通用的恢復(fù)機(jī)制對(duì)硬件進(jìn)行重置,驅(qū)動(dòng)程序再次讀取相關(guān)信息可以正常運(yùn)行,而對(duì)于固化前的驅(qū)動(dòng),由于發(fā)生了短暫性的硬件故障,導(dǎo)致了驅(qū)動(dòng)不能正常運(yùn)行下去。正是由于我們插入的修復(fù)代碼和引入驅(qū)動(dòng)的恢復(fù)機(jī)制,當(dāng)發(fā)生硬件故障時(shí)候,我們的驅(qū)動(dòng)程序能夠容忍硬件瞬時(shí)故障,從而實(shí)現(xiàn)在軟件中容忍硬件故障的目的。
對(duì)于故障的報(bào)告分析,我們主要是報(bào)告設(shè)備超時(shí)(驅(qū)動(dòng)代碼發(fā)生無限輪洵)和報(bào)告驅(qū)動(dòng)代碼數(shù)組越界。由于Linux沒有故障管理服務(wù),我們使用printk來實(shí)現(xiàn)系統(tǒng)日志。系統(tǒng)管理員可以通過在終端輸入命令dmesg或者進(jìn)入Linux系統(tǒng)日志目錄進(jìn)行查看。對(duì)于設(shè)備超時(shí)的故障報(bào)告主要是當(dāng)由于硬件瞬時(shí)故障而導(dǎo)致驅(qū)動(dòng)程序發(fā)生無限輪詢錯(cuò)誤的時(shí)候通過printk函數(shù)以infinite loop為標(biāo)識(shí)寫系統(tǒng)日志。系統(tǒng)管理員通過infinite loop為標(biāo)識(shí)查看是否發(fā)生該類故障。對(duì)于數(shù)組越界的錯(cuò)誤報(bào)告主要是當(dāng)驅(qū)動(dòng)代碼由于硬件故障而發(fā)生數(shù)組越界錯(cuò)誤的時(shí)候通過printk函數(shù)以Array out of range為標(biāo)識(shí)寫系統(tǒng)日志。系統(tǒng)管理員通過Arrav out of range查看是否發(fā)生數(shù)組越界故障。通過dmesg查看系統(tǒng)日志發(fā)現(xiàn),我們能正確的報(bào)告發(fā)生的相關(guān)驅(qū)動(dòng)故障,從而方便管理員對(duì)故障進(jìn)行管理和維護(hù)。
4 測試評(píng)估
4.1 功能測試評(píng)估
為了評(píng)估自動(dòng)分析工具的功能準(zhǔn)確性,我們定義誤檢率和漏檢率。誤檢率即某處不是受硬件瞬時(shí)故障影響的敏感代碼,而自動(dòng)分析工具卻標(biāo)注其為敏感代碼,在整個(gè)掃描過程中出現(xiàn)這種誤報(bào)的概率。某處是受硬件瞬時(shí)故障影響的敏感代碼,但自動(dòng)分析工具卻沒有標(biāo)注其為敏感代碼,這種漏報(bào)的概率稱為漏報(bào)率。
本文主要是對(duì)2.6.18的內(nèi)核版本應(yīng)用我們的自動(dòng)分析工具,驗(yàn)證了這種分析方法能夠正確的查找到所有驅(qū)動(dòng)模塊的敏感代碼,按照驅(qū)動(dòng)類劃分查詢到的敏感代碼數(shù)量如下表1所示。
通過靜態(tài)分析和有效性檢查,我們對(duì)整個(gè)Linux內(nèi)核驅(qū)動(dòng)代碼進(jìn)行全盤分析掃描,主要是查找兩類硬件依賴故障即無限輪詢和數(shù)組越界錯(cuò)誤。對(duì)于短暫性硬件故障導(dǎo)致驅(qū)動(dòng)程序的無限輪詢,在網(wǎng)卡驅(qū)動(dòng)類中查找到110個(gè)潛在的錯(cuò)誤,在scsi驅(qū)動(dòng)類290個(gè)潛在的錯(cuò)誤,在整個(gè)Linux驅(qū)動(dòng)中總體查找到740個(gè)錯(cuò)誤。對(duì)于靜態(tài)數(shù)組越界的敏感代碼,我們?cè)贚inux驅(qū)動(dòng)中共查找到43個(gè)潛在的錯(cuò)誤。上述錯(cuò)誤充分說明潛在的硬件依賴性錯(cuò)誤在內(nèi)核驅(qū)動(dòng)代碼中是普遍存在的且是亟待的問題。
通過對(duì)2.6.18和3.2.1內(nèi)核版本的驅(qū)動(dòng)源碼使用自動(dòng)分析工具進(jìn)行比較,內(nèi)核版本為3.2.1的內(nèi)核源碼所檢測到的敏感代碼比2.6.18少,并通過抽樣檢查其誤報(bào)率和漏報(bào)率均較小且差別不大。由于內(nèi)核版本為3.2.1是2.6.18的升級(jí),所以檢測到的敏感代碼少是合理的。比較結(jié)果證明,我們的自動(dòng)分析工具能夠?qū)Σ煌瑑?nèi)核版本的驅(qū)動(dòng)的敏感代碼進(jìn)行準(zhǔn)確的分析。
我們針對(duì)本機(jī)的網(wǎng)卡驅(qū)動(dòng)通過引用故障注入工具模擬短暫性的硬件故障,對(duì)修改前和修改后的驅(qū)動(dòng)進(jìn)行測試,修改前的網(wǎng)卡驅(qū)動(dòng)會(huì)產(chǎn)生無限輪詢錯(cuò)誤導(dǎo)致本機(jī)網(wǎng)卡驅(qū)動(dòng)出現(xiàn)無法修復(fù)的問題,而修改后的驅(qū)動(dòng)能正確的容忍硬件依賴性故障,喚起通用的驅(qū)動(dòng)恢復(fù)服務(wù)并告知系統(tǒng)管理員發(fā)生了短暫性的硬件故障,達(dá)到我們預(yù)期的效果。
4.2 性能評(píng)估測試
性能評(píng)估主要是評(píng)估檢測敏感代碼系統(tǒng)能力及故障恢復(fù)性能,識(shí)別出系統(tǒng)存在的弱點(diǎn)并驗(yàn)證該系統(tǒng)的穩(wěn)定性。本文采用系統(tǒng)性能測試,對(duì)系統(tǒng)性能進(jìn)行全面的評(píng)估,主要包括宏觀性能測試和微觀性能測試。宏觀性能測試主要是對(duì)檢測敏感代碼系統(tǒng)的耗時(shí)和準(zhǔn)確性進(jìn)行評(píng)估。微觀性能分析主要是對(duì)自動(dòng)分析工具進(jìn)行CPU利用率評(píng)估。
本文所采用的測試是在Ubuntu 12.04系統(tǒng)下完成,該系統(tǒng)中Linux內(nèi)核版為3.11.0-26,GCC編譯器版本4.8.1,計(jì)算機(jī)硬件配置為CPU Pentium Dual-Core,內(nèi)存2G,硬盤200G。
本文宏觀性能測試主要測試檢測敏感代碼系統(tǒng)的耗時(shí)及其準(zhǔn)確性。檢測耗時(shí)主要方法是使用UNIXdate命令。在對(duì)Linux驅(qū)動(dòng)源碼進(jìn)行遍歷掃描的腳本中,增加驅(qū)動(dòng)分析開始時(shí)間及結(jié)束時(shí)間,通過計(jì)算得出分析檢測驅(qū)動(dòng)代碼所消耗的時(shí)間為4700s。對(duì)檢測到的敏感代碼的準(zhǔn)確性我們主要是采用加權(quán)隨機(jī)抽樣的方式,通過對(duì)自動(dòng)檢測敏感代碼的結(jié)果和手動(dòng)抽樣檢查進(jìn)行比較,其檢測到的敏感代碼的準(zhǔn)確率較高。
微觀性能評(píng)估主要是對(duì)自動(dòng)分析工具進(jìn)行CPU利用率評(píng)估,檢測方法主要是利用Linux操作系統(tǒng)的ps命令獲取該分析工具的CPU利用率。在對(duì)內(nèi)核驅(qū)動(dòng)代碼進(jìn)行自動(dòng)分析的過程中,我們使用ps命令獲取其CPU利用率為2.2%,結(jié)果表明,該工具性能開銷較小,符合我們的設(shè)計(jì)要求。
5 結(jié)論
系統(tǒng)的可靠性由于設(shè)備及對(duì)應(yīng)驅(qū)動(dòng)的可靠性而受到限制,Linux系統(tǒng)出現(xiàn)的很多故障都是由于硬件瞬時(shí)故障導(dǎo)致的。為解決該問題,本文提出一種在驅(qū)動(dòng)軟件中容忍硬件瞬時(shí)故障的機(jī)制,討論了面向硬件瞬時(shí)故障的驅(qū)動(dòng)程序敏感代碼的自動(dòng)分析方法,通過對(duì)Linux驅(qū)動(dòng)源碼進(jìn)行預(yù)處理、詞法分析、語法分析和靜態(tài)分析,查找出可能產(chǎn)生無限輪詢和靜態(tài)數(shù)組越界的敏感代碼并進(jìn)行標(biāo)注。為修復(fù)該類敏感代碼可能引起的驅(qū)動(dòng)問題,我們通過插入時(shí)間檢查和范圍檢查,并引入了一個(gè)通用的恢復(fù)服務(wù)隱匿驅(qū)動(dòng)程序?qū)Πl(fā)生短暫性硬件故障的設(shè)備進(jìn)行重置,驅(qū)動(dòng)重新讀取寄存器中的硬件數(shù)據(jù)以達(dá)到修復(fù)的目的。同時(shí),當(dāng)發(fā)生短暫的硬件依賴性故障的時(shí)候,我們通過系統(tǒng)日志的方式通知管理員硬件發(fā)生問題,方便系統(tǒng)管理員對(duì)系統(tǒng)進(jìn)行管理和維護(hù)。由于偶發(fā)性的硬件故障比較罕見的發(fā)生,為測試實(shí)驗(yàn)結(jié)果,我們使用了故障注入工具來模擬我們期望的硬件故障,通過測試,經(jīng)加固后的驅(qū)動(dòng)程序能夠很好的容忍硬件瞬時(shí)故障,從而很好的實(shí)現(xiàn)了在軟件中容忍硬件故障的目的。