本發(fā)明屬于計(jì)算機(jī)操作系統(tǒng)安全領(lǐng)域,即一種基于內(nèi)核模塊隔離的保護(hù)內(nèi)核模塊安全的研究,涉及一種針對(duì)linux內(nèi)核頁(yè)表隔離的功能調(diào)用改造方法。
背景技術(shù):
隨著技術(shù)的發(fā)展,linux系統(tǒng)已在各行各業(yè)都得到了廣泛的應(yīng)用,這其中就包括金融、保險(xiǎn)、政府機(jī)關(guān)等對(duì)安全性要求較高的行業(yè),然而linux內(nèi)核作為系統(tǒng)中最重要的部分,其安全性一直為人所詬病。導(dǎo)致linux安全性不高的原因有很多,最根本的原因在于其宏內(nèi)核的設(shè)計(jì)模式使得內(nèi)核中的各個(gè)模塊都能以最高權(quán)限訪問(wèn)整個(gè)內(nèi)核地址空間,從而任意模塊的漏洞都可能會(huì)擴(kuò)散到內(nèi)核的其他模塊,最終導(dǎo)致整個(gè)系統(tǒng)的崩潰。
隨著惡意攻擊手段的不斷增加,包括沙箱、可信技術(shù)及訪問(wèn)控制在內(nèi)的傳統(tǒng)防御機(jī)制已無(wú)法滿足內(nèi)核的安全性。為此,學(xué)界和工業(yè)界引入了安全隔離機(jī)制來(lái)提供一個(gè)安全隔離的運(yùn)行環(huán)境以保護(hù)內(nèi)核。根據(jù)隔離機(jī)制實(shí)現(xiàn)方式的不同,我們可以將其歸納為硬件隔離技術(shù)和軟件隔離技術(shù)兩類(lèi)。所謂硬件隔離技術(shù),是指對(duì)相關(guān)芯片設(shè)計(jì)一個(gè)專(zhuān)門(mén)用于存儲(chǔ)系統(tǒng)關(guān)鍵數(shù)據(jù)的安全硬件模塊,并通過(guò)硬件限制其它模塊的非法訪問(wèn),以此達(dá)到隔離的目的,常見(jiàn)的應(yīng)用模型有可信平臺(tái)模塊tpm和trustzone安全處理架構(gòu)兩種。然而硬件隔離技術(shù)往往依賴(lài)于硬件類(lèi)型,這會(huì)降低隔離產(chǎn)品的通用性。所謂軟件隔離技術(shù),是指在軟件層構(gòu)建一個(gè)安全的隔離運(yùn)行環(huán)境用于存放系統(tǒng)中的敏感數(shù)據(jù)和相關(guān)代碼,使這些數(shù)據(jù)和代碼不會(huì)受到外界惡意攻擊的影響。虛擬化隔離技術(shù)是最常見(jiàn)的軟件隔離技術(shù)之一,它之所以能作為系統(tǒng)安全隔離的手段之一,是因?yàn)樘摂M機(jī)管理軟件能攔截并模擬處理客戶(hù)操作系統(tǒng)的敏感指令,阻止客戶(hù)機(jī)對(duì)主機(jī)的非法操作,并且保證各個(gè)客戶(hù)機(jī)的獨(dú)立性,使得某個(gè)客戶(hù)機(jī)的惡意操作不會(huì)擴(kuò)散到其它客戶(hù)機(jī)上。然而,虛擬機(jī)目前只能隔離一些動(dòng)態(tài)載入的驅(qū)動(dòng)模塊,而對(duì)于包括文件系統(tǒng)在內(nèi)的靜態(tài)模塊的隔離困難較大。
針對(duì)以上兩種內(nèi)核隔離機(jī)制的缺陷,提出了基于內(nèi)存頁(yè)表不可見(jiàn)性的內(nèi)核隔離方案。具體做法是將被隔離模塊的代碼和數(shù)據(jù)單獨(dú)映射到由特定頁(yè)表控制的物理地址空間中,并控制該頁(yè)表的訪問(wèn)區(qū)間,以此實(shí)現(xiàn)模塊間的隔離。然而原linux系統(tǒng)采用宏內(nèi)核模式來(lái)設(shè)計(jì)模塊間的功能調(diào)用機(jī)制,全部過(guò)程都處于同一個(gè)進(jìn)程上下文中,但在內(nèi)存不可見(jiàn)的情況下,一個(gè)進(jìn)程是無(wú)法訪問(wèn)兩個(gè)被隔離模塊的。如果不對(duì)原功能調(diào)用形式進(jìn)行改造,被隔離模塊依舊會(huì)通過(guò)直接調(diào)用接口函數(shù)的方式訪問(wèn)其它模塊,屆時(shí)相關(guān)的內(nèi)存訪問(wèn)操作會(huì)被拒絕,導(dǎo)致系統(tǒng)不能完整地處理用戶(hù)請(qǐng)求。
針對(duì)上述原linux內(nèi)核功能調(diào)用的缺陷,本發(fā)明提出了一種針對(duì)linux內(nèi)核頁(yè)表隔離的功能調(diào)用改造方法,即分別在文件系統(tǒng)和內(nèi)核中插入存根子模塊和回調(diào)子模塊,并將功能調(diào)用由原來(lái)的宏內(nèi)核模式改成微內(nèi)核模式,使系統(tǒng)在保證內(nèi)核代碼和數(shù)據(jù)的安全性的同時(shí),能夠讓被隔離模塊正常訪問(wèn)內(nèi)核代碼并正確處理用戶(hù)空間的服務(wù)請(qǐng)求。
技術(shù)實(shí)現(xiàn)要素:
發(fā)明目的:本發(fā)明所要解決的技術(shù)問(wèn)題是針對(duì)原linux內(nèi)核的功能調(diào)用方式無(wú)法適用于基于內(nèi)存頁(yè)表不可見(jiàn)性的內(nèi)核模塊隔離方案這一問(wèn)題,提出了一種針對(duì)linux內(nèi)核頁(yè)表隔離的功能調(diào)用改造方法。
為了解決以上問(wèn)題,本發(fā)明公開(kāi)了一種針對(duì)linux內(nèi)核頁(yè)表隔離的功能調(diào)用改造方法,該方法所有的步驟均運(yùn)行與linux平臺(tái),用于將被隔離模塊間的功能調(diào)用方式由原來(lái)的宏內(nèi)核模式改為微內(nèi)核模式,以允許被隔離模塊依舊可以正常的訪問(wèn)內(nèi)核中其它模塊的代碼和數(shù)據(jù)。
所述針對(duì)linux內(nèi)核頁(yè)表隔離的功能調(diào)用改造方法的步驟如下:
包括如下步驟:
步驟1,在clang編譯器中編寫(xiě)插件,利用該插件分析被隔離模塊并獲得其函數(shù)調(diào)用關(guān)系圖;
步驟2,編寫(xiě)查找算法在函數(shù)調(diào)用關(guān)系圖中查找其它模塊的所有接口函數(shù)調(diào)用點(diǎn);
步驟3,根據(jù)所得的接口函數(shù)編寫(xiě)相應(yīng)的存根函數(shù)和回調(diào)函數(shù),并分別存入被隔離模塊的存根子模塊以及內(nèi)核的回調(diào)子模塊中;
步驟4,在每個(gè)接口函數(shù)調(diào)用點(diǎn)處都用對(duì)應(yīng)的存根函數(shù)替換原接口函數(shù);
步驟5,針對(duì)數(shù)據(jù)處理過(guò)程中的一致性問(wèn)題,提出了對(duì)進(jìn)程控制塊進(jìn)行重定向的方法。
本發(fā)明步驟1包括如下步驟:
步驟1-1,在clang編譯器內(nèi)部編寫(xiě)相關(guān)插件并重新編譯llvm,使其在構(gòu)造完抽象語(yǔ)法樹(shù)后都以深度優(yōu)先的范式遍歷樹(shù)中的節(jié)點(diǎn),并過(guò)濾出調(diào)用函數(shù)節(jié)點(diǎn)、被調(diào)用函數(shù)節(jié)點(diǎn)以及被調(diào)用函數(shù)指針節(jié)點(diǎn);
步驟1-2,用步驟1-1得到的編譯器插件分析linux內(nèi)核源碼中的被隔離模塊部分,得到其中包括函數(shù)指針在內(nèi)的函數(shù)調(diào)用關(guān)系圖;為了解決歧義性問(wèn)題,還必須將架構(gòu)相關(guān)文件和配置文件導(dǎo)入插件中;
步驟1-3,將步驟1-2得到的函數(shù)調(diào)用關(guān)系信息格式化到指定的哈希表中,其中關(guān)鍵字為調(diào)用函數(shù)名,值為包括函數(shù)指針在內(nèi)的被調(diào)用函數(shù)列表;無(wú)論是調(diào)用函數(shù)名還是被調(diào)用函數(shù)名都以字符串形式保存,并且此時(shí)鍵值對(duì)中無(wú)模塊標(biāo)簽。
本發(fā)明步驟1-1包括以下步驟:
步驟1-1-1,重載handletranslationunit函數(shù),在該函數(shù)內(nèi)部調(diào)用traversedecl函數(shù),從而讓clang編譯器每次構(gòu)造完抽象語(yǔ)法樹(shù)后都以深度優(yōu)先的范式遍歷樹(shù)中的節(jié)點(diǎn);
步驟1-1-2,重載的visitfunctiondecl函數(shù),使得clang編譯器每當(dāng)遇到函數(shù)聲明/類(lèi)型節(jié)點(diǎn)時(shí),都會(huì)自動(dòng)過(guò)濾掉函數(shù)聲明的情況,并將保留下來(lái)的函數(shù)定義信息作為調(diào)用函數(shù)保存;
步驟1-1-3,重載的visitdeclrefexpr函數(shù),使得clang編譯器每當(dāng)遇到引用表達(dá)式類(lèi)型節(jié)點(diǎn)時(shí),都會(huì)自動(dòng)過(guò)濾掉非函數(shù)表達(dá)式的情況,并將保留下來(lái)的函數(shù)表達(dá)式信息作為被調(diào)用函數(shù)保存;
步驟1-1-4,重載的visitmemberexpr函數(shù),使得clang編譯器每當(dāng)遇到成員表達(dá)式類(lèi)型節(jié)點(diǎn)時(shí),都會(huì)自動(dòng)過(guò)濾掉非函數(shù)指針的情況,并將保留下來(lái)的函數(shù)指針信息作為被調(diào)用函數(shù)指針保存。
本發(fā)明步驟2包括以下步驟:
步驟2-1,從內(nèi)核鏡像vmlinux中提取各個(gè)模塊的函數(shù)符號(hào)信息和接口函數(shù)信息,其中每個(gè)函數(shù)項(xiàng)都包含對(duì)應(yīng)的模塊信息;將函數(shù)符號(hào)信息和接口函數(shù)信息按需存放到函數(shù)符號(hào)表和接口函數(shù)表中;
步驟2-2,遍歷步驟1中的得到的被隔離模塊的函數(shù)調(diào)用關(guān)系圖,對(duì)每個(gè)調(diào)用函數(shù)或被調(diào)用函數(shù)都在步驟2-1中的得到的函數(shù)符號(hào)表中搜索對(duì)應(yīng)的模塊信息,并將得到的模塊信息以字符串標(biāo)簽的形式打印到函數(shù)調(diào)用關(guān)系圖中的相應(yīng)位置;
步驟2-3,設(shè)計(jì)并實(shí)現(xiàn)了按模塊查找接口函數(shù)調(diào)用點(diǎn)的功能;利用該算法分析步驟2-2中得到的帶模塊標(biāo)簽的函數(shù)調(diào)用關(guān)系圖,以獲取被隔離模塊中所有調(diào)用其它模塊接口函數(shù)的位置;
步驟2-4,設(shè)計(jì)并實(shí)現(xiàn)了按函數(shù)查找接口函數(shù)調(diào)用點(diǎn)的功能;利用該算法分析步驟2-2中得到的帶模塊標(biāo)簽的函數(shù)調(diào)用關(guān)系圖,以獲取被查找函數(shù)的調(diào)用關(guān)系鏈中所有調(diào)用其它模塊接口函數(shù)的位置。
本發(fā)明步驟2-1包括以下步驟:
步驟2-1-1,調(diào)用nm命令從內(nèi)核鏡像vmlinux中提取出帶位置信息的內(nèi)核符號(hào)表;
步驟2-1-2,根據(jù)符號(hào)類(lèi)型從步驟2-1-1得到的內(nèi)核符號(hào)表中篩選出函數(shù)符號(hào)信息和接口函數(shù)信息,其中將類(lèi)型為t或t符號(hào)整理為函數(shù)符號(hào)信息,而將類(lèi)型為t的符號(hào)整理為接口函數(shù)信息;
步驟2-1-3,設(shè)計(jì)兩種哈希表,分別以函數(shù)名和函數(shù)地址為關(guān)鍵字;將步驟2-1-2得到的函數(shù)符號(hào)信息存入以函數(shù)名為關(guān)鍵字的哈希表中,并將該哈希表作為函數(shù)符號(hào)表;將步驟2-1-2得到的接口函數(shù)表按兩種格式分別存入以函數(shù)名為關(guān)鍵字的哈希表和已函數(shù)地址為關(guān)鍵字的哈希表中,這兩個(gè)哈希表都稱(chēng)為接口函數(shù)表。
本發(fā)明步驟2-3包括以下步驟:
步驟2-3-1,將函數(shù)調(diào)用關(guān)系圖中的第一個(gè)關(guān)鍵字函數(shù)(即第一個(gè)調(diào)用函數(shù))作為當(dāng)前關(guān)鍵字函數(shù);
步驟2-3-2,獲得當(dāng)前關(guān)鍵字函數(shù)對(duì)應(yīng)的被調(diào)用函數(shù)列表;遍歷該被調(diào)用函數(shù)列表,依次檢查被調(diào)用函數(shù)的模塊標(biāo)簽是否是被查找模塊或頭文件:若是,則直接跳到下一被調(diào)用函數(shù);否則,將當(dāng)前關(guān)鍵字函數(shù)和該被調(diào)用函數(shù)組成的二元組作為接口函數(shù)調(diào)用點(diǎn)記錄下來(lái);
步驟2-3-3,待該關(guān)鍵字函數(shù)對(duì)應(yīng)的被調(diào)用函數(shù)值列表遍歷完畢后,檢查函數(shù)調(diào)用關(guān)系圖中是否還有下一個(gè)關(guān)鍵字未被處理:若有,則獲取下一個(gè)關(guān)鍵字函數(shù)作為當(dāng)前關(guān)鍵字函數(shù)返回步驟2-3-2繼續(xù)執(zhí)行;否則,結(jié)束查找算法。
本發(fā)明步驟2-4包括以下步驟:
步驟2-4-1,將被查找函數(shù)作為當(dāng)前關(guān)鍵字函數(shù);
步驟2-4-2,深度優(yōu)先遍歷當(dāng)前關(guān)鍵字函數(shù)對(duì)應(yīng)的被調(diào)用函數(shù)值列表,若表項(xiàng)函數(shù)在目標(biāo)模塊中,則將當(dāng)前關(guān)鍵字函數(shù)和該被調(diào)用函數(shù)組成的二元組作為接口函數(shù)調(diào)用點(diǎn)記錄下來(lái);否則,執(zhí)行步驟2-4-3;
步驟2-4-3,若表項(xiàng)函數(shù)位于頭文件或所在模塊與被查找函數(shù)相同,則以該表項(xiàng)函數(shù)作為當(dāng)前關(guān)鍵字函數(shù)返回步驟2-4-2中繼續(xù)查找;否則,直接取下一表項(xiàng)函數(shù)作為當(dāng)前關(guān)鍵字返回步驟2-4-2中繼續(xù)查找,直到遍歷結(jié)束。
本發(fā)明步驟3包括以下步驟:
步驟3-1,設(shè)計(jì)并實(shí)現(xiàn)了一種接口函數(shù)改造方案:在被隔離模塊和內(nèi)核中分別設(shè)計(jì)并實(shí)現(xiàn)存根子模塊和回調(diào)子模塊;當(dāng)被隔離模塊需要訪問(wèn)內(nèi)核中的代碼或數(shù)據(jù)時(shí)會(huì)重定向到存根子模塊中,存根子模塊負(fù)責(zé)打包消息并通過(guò)ipc傳遞到內(nèi)核中;回調(diào)子模塊收到消息后交由回調(diào)子模塊執(zhí)行,回調(diào)子模塊負(fù)責(zé)拆解消息塊以獲取其中的參數(shù)等信息,之后執(zhí)行真正的工作函數(shù)(即原接口函數(shù)),最后將返回值打包反饋給被隔離模塊;
步驟3-2,設(shè)計(jì)并實(shí)現(xiàn)了存根子模塊和回調(diào)子模口之間用于ipc傳輸?shù)南K,其內(nèi)部包含六個(gè)成員對(duì)象,分別是當(dāng)前進(jìn)程的current、回調(diào)函數(shù)指針、指向?qū)崊⑷萜鞯姆盒椭羔?、指向返回值的泛型指針、結(jié)束位以及反饋消息的隊(duì)列號(hào);其中當(dāng)前進(jìn)程的current值用于解決數(shù)據(jù)一致性問(wèn)題,回調(diào)函數(shù)指針用于告訴內(nèi)核需要調(diào)用哪個(gè)回調(diào)函數(shù)處理,指向?qū)崊⑷萜鞯闹羔樣糜诖鎯?chǔ)各種類(lèi)型和數(shù)量的實(shí)參,返回值指針用于存儲(chǔ)各種類(lèi)型的返回值,結(jié)束位用于指示核心態(tài)工作是否結(jié)束,反饋消息隊(duì)列號(hào)用于告訴內(nèi)核將帶有返回值的消息塊發(fā)送到哪個(gè)消息隊(duì)列中;
步驟3-3,設(shè)計(jì)并實(shí)現(xiàn)了用于存儲(chǔ)各種類(lèi)型和數(shù)量實(shí)參的參數(shù)容器,本發(fā)明根據(jù)參數(shù)數(shù)量設(shè)計(jì)了八種實(shí)參容器,實(shí)現(xiàn)過(guò)程中利用c語(yǔ)言中的宏定義來(lái)模擬高級(jí)語(yǔ)言中的模板,并通過(guò)模板實(shí)例化的方式來(lái)統(tǒng)一傳輸各種類(lèi)型和數(shù)量的實(shí)參。
本發(fā)明步驟3-1包括以下步驟:
步驟3-1-1,根據(jù)步驟2-1中得到的接口函數(shù)表,為每個(gè)接口函數(shù)都編寫(xiě)對(duì)應(yīng)的存根函數(shù)和回調(diào)函數(shù),分別存放到被隔離模塊的存根子模塊和內(nèi)核的回調(diào)子模塊中;
步驟3-1-2,存根函數(shù)的執(zhí)行過(guò)程:生成并初始化消息塊,包括注冊(cè)回調(diào)函數(shù)、被隔離模塊的當(dāng)前current值、反饋消息隊(duì)列號(hào);創(chuàng)建并初始化參數(shù)容器,并將其掛載到消息塊中;調(diào)用消息模塊提供的api函數(shù)msgsnd發(fā)送消息;在先前注冊(cè)的消息隊(duì)列號(hào)上等待內(nèi)核的反饋消息;解析反饋消息中的返回值并繼續(xù)執(zhí)行下一指令;
步驟3-1-2,回調(diào)函數(shù)的執(zhí)行過(guò)程:解析獲得的消息塊并用其中的pcb指針偽裝自己的current,以此實(shí)現(xiàn)數(shù)據(jù)一致性;創(chuàng)建參數(shù)容器,并以此解析消息塊中的具體參數(shù);將具體參數(shù)傳入真正的工作函數(shù)(即原接口函數(shù)),并將返回值存入原消息塊的相關(guān)位置;調(diào)用消息模塊提供的api函數(shù)msgsnd,將原消息塊(此時(shí)存有返回值)發(fā)送到消息塊中指定的消息隊(duì)列中。
本發(fā)明步驟4需要根據(jù)被調(diào)用函數(shù)的類(lèi)型進(jìn)行分類(lèi)操作:
若接口函數(shù)調(diào)用點(diǎn)處調(diào)用的是一個(gè)普通函數(shù),則直接在源碼中用對(duì)應(yīng)的存根函數(shù)替換原接口函數(shù);若接口函數(shù)調(diào)用點(diǎn)處調(diào)用的是一個(gè)函數(shù)指針,則先在步驟2-1-3中得到的以函數(shù)地址為關(guān)鍵字的接口函數(shù)表中查詢(xún)?cè)摵瘮?shù)指針是否指向一個(gè)接口函數(shù)的指針,若是,則調(diào)用對(duì)應(yīng)的存根函數(shù);否則,直接執(zhí)行該函數(shù)指針。
本發(fā)明步驟5包括以下步驟:
步驟5-1,為被隔離模塊保存一個(gè)獨(dú)一無(wú)二而的全局變量temp(假設(shè)被隔離模塊是單進(jìn)程的),用來(lái)存儲(chǔ)內(nèi)核傳過(guò)來(lái)的pcb指針;
步驟5-2,被隔離模塊每次接收到新的消息塊時(shí),都用該消息塊中的current成員去更新全局變量temp;
步驟5-3,根據(jù)需要重定義current:通過(guò)get_current()判斷當(dāng)前進(jìn)程是被隔離模塊進(jìn)程還是內(nèi)核進(jìn)程,若是被隔離模塊進(jìn)程,則返回全局變量temp;若是內(nèi)核進(jìn)程,則直接返回get_current()的結(jié)果。
附圖說(shuō)明
下面結(jié)合附圖和具體實(shí)施方式對(duì)本發(fā)明做更進(jìn)一步的具體說(shuō)明,本發(fā)明的上述或其他方面的優(yōu)點(diǎn)將會(huì)變得更加清楚。
圖1為本發(fā)明的背景圖,即基于內(nèi)存頁(yè)表不可見(jiàn)性的內(nèi)核隔離框架圖。
圖2為本發(fā)明的實(shí)現(xiàn)流程圖
圖3為函數(shù)調(diào)用關(guān)系分析軟件的內(nèi)部流程圖
圖4為接口函數(shù)調(diào)用點(diǎn)查找過(guò)程的原理圖
圖5為改造后的功能調(diào)用框架圖
圖6為進(jìn)程控制塊重定向的原理圖
具體實(shí)施方式
下面結(jié)合附圖對(duì)本發(fā)明做進(jìn)一步說(shuō)明。
本發(fā)明提出了一種針對(duì)linux內(nèi)核頁(yè)表隔離的功能調(diào)用改造方法,通過(guò)對(duì)linux系統(tǒng)的模塊間功能調(diào)用方式進(jìn)行改造,以保證隔離后被隔離模塊能正常訪問(wèn)內(nèi)核中其它模塊的代碼和數(shù)據(jù)。
圖1為基于內(nèi)存頁(yè)表不可見(jiàn)性的內(nèi)核隔離框架圖,展示了該隔離環(huán)境下一次完整的用戶(hù)空間服務(wù)請(qǐng)求的執(zhí)行過(guò)程,具體步驟如下:
步驟1,應(yīng)用程序發(fā)出的與被隔離模塊相關(guān)的服務(wù)請(qǐng)求時(shí)會(huì)被hook到被隔離模塊進(jìn)程中執(zhí)行;
步驟2,當(dāng)被隔離模塊模塊需要訪問(wèn)內(nèi)核其它模塊的代碼和數(shù)據(jù)時(shí),并不會(huì)直接調(diào)用原來(lái)的接口函數(shù),取而代之的是調(diào)用存根子模塊中對(duì)應(yīng)的存儲(chǔ)函數(shù),這些存根函數(shù)負(fù)責(zé)生成消息塊并選擇合適的消息隊(duì)列號(hào),然后通過(guò)消息模塊發(fā)送到內(nèi)核中的回調(diào)子模塊;
步驟3,內(nèi)核收到消息后交由回調(diào)子模塊處理,回調(diào)子模塊調(diào)用消息塊中先前注冊(cè)的回調(diào)函數(shù)執(zhí)行真正的工作函數(shù),并將返回值通過(guò)消息模塊返回給被隔離模塊以便執(zhí)行后續(xù)指令;
步驟4,當(dāng)被隔離模塊完成整個(gè)服務(wù)請(qǐng)求后,會(huì)將最終的返回值交給內(nèi)核,然后由內(nèi)核交給用戶(hù)應(yīng)用程序。
圖2為本發(fā)明的實(shí)現(xiàn)流程圖,展示了功能調(diào)用改造的實(shí)現(xiàn)過(guò)程,具體步驟如下:
步驟1,在clang編譯器中編寫(xiě)插件,利用該插件分析被隔離模塊并獲得其函數(shù)調(diào)用關(guān)系圖,具體插件的實(shí)現(xiàn)方法如圖3所示;
步驟2,編寫(xiě)查找算法在函數(shù)調(diào)用關(guān)系圖中查找其它模塊的所有接口函數(shù)調(diào)用點(diǎn),具體接口函數(shù)調(diào)用點(diǎn)查找算法的實(shí)現(xiàn)方法如圖4所示;
步驟3,根據(jù)所得的接口函數(shù)編寫(xiě)相應(yīng)的存根函數(shù)和回調(diào)函數(shù),并分別存入被隔離模塊的存根子模塊以及內(nèi)核的回調(diào)子模塊中,存根子模塊和回調(diào)子模塊的內(nèi)部構(gòu)造如圖5所示;
步驟4,在每個(gè)接口函數(shù)調(diào)用點(diǎn)處都用對(duì)應(yīng)的存根函數(shù)替換原接口函數(shù),具體工作步驟如下:
步驟4-1,判斷當(dāng)前接口函數(shù)調(diào)用點(diǎn)處調(diào)用的是一個(gè)普通函數(shù)還是一個(gè)函數(shù)指針,若是一個(gè)普通函數(shù),則執(zhí)行步驟4-2;若是一個(gè)函數(shù)指針,則執(zhí)行步驟4-3;
步驟4-2,直接在源碼中用對(duì)應(yīng)的存根函數(shù)替換原接口函數(shù);
步驟4-3,先在以函數(shù)地址為關(guān)鍵字的接口函數(shù)表中查詢(xún)?cè)摵瘮?shù)指針是否指向一個(gè)接口函數(shù)的指針,若是,則調(diào)用對(duì)應(yīng)的存根函數(shù);否則,直接執(zhí)行該函數(shù)指針。
步驟5,針對(duì)數(shù)據(jù)處理過(guò)程中的一致性問(wèn)題,設(shè)計(jì)并實(shí)現(xiàn)了對(duì)進(jìn)程控制塊進(jìn)行重定向的方法,進(jìn)程控制塊重定向的具體實(shí)現(xiàn)方法如圖6所示。
圖3為函數(shù)調(diào)用關(guān)系分析軟件(即clang編譯器插件)的內(nèi)部流程圖,展示了本發(fā)明中函數(shù)調(diào)用關(guān)系分析軟件模塊的實(shí)現(xiàn)方法,具體步驟如下:
步驟1,分別對(duì)visitfunctiondecl函數(shù)、visitdeclrefexpr函數(shù)以及visitmemberexpr函數(shù)進(jìn)行重載,這些被重載的函數(shù)用于分析抽象語(yǔ)法樹(shù)并得到包括函數(shù)指針在內(nèi)的函數(shù)調(diào)用關(guān)系圖,具體實(shí)現(xiàn)原理如下:
步驟1-1,重載visitfunctiondecl函數(shù),內(nèi)部調(diào)用isthisdeclarationadefinition函數(shù)用于判斷當(dāng)前ast節(jié)點(diǎn)表示的是一個(gè)函數(shù)聲明還是一個(gè)函數(shù)定義,若表示的是一個(gè)函數(shù)定義,則將當(dāng)前函數(shù)作為關(guān)鍵字保存到哈希表中,并為該關(guān)鍵字函數(shù)創(chuàng)建一個(gè)空的值列表用于保存它的被調(diào)用函數(shù)集,否則,直接跳過(guò);該步驟用于獲得函數(shù)調(diào)用關(guān)系圖中的調(diào)用函數(shù)信息;
步驟1-2,重載visitdeclrefexpr函數(shù),內(nèi)部利用動(dòng)態(tài)類(lèi)型轉(zhuǎn)換判斷當(dāng)前ast節(jié)點(diǎn)是否是函數(shù)類(lèi)型節(jié)點(diǎn),若是,則將當(dāng)前函數(shù)作為被調(diào)用函數(shù)保存到最近關(guān)鍵字函數(shù)所對(duì)應(yīng)的值列表中,否則,直接跳過(guò);該步驟用于獲得函數(shù)調(diào)用關(guān)系圖中的被調(diào)用函數(shù)信息;
步驟1-3,重載visitmemberexpr函數(shù),內(nèi)部調(diào)用isfunctionpointertype函數(shù)用于當(dāng)前ast節(jié)點(diǎn)表示的是否是一個(gè)函數(shù)指針,若是,則將當(dāng)前指針作為被調(diào)用函數(shù)指針保存到最近關(guān)鍵字函數(shù)所對(duì)應(yīng)的值列表中,否則,直接跳過(guò);該步驟用于獲得函數(shù)調(diào)用關(guān)系圖中的被調(diào)用函數(shù)指針信息。
步驟2,重載handletranslationunit函數(shù),內(nèi)部traversedecl函數(shù)用于以深度優(yōu)先的方式遍歷ast的每個(gè)節(jié)點(diǎn),并根據(jù)節(jié)點(diǎn)的類(lèi)型調(diào)用相應(yīng)的重載訪問(wèn)函數(shù)進(jìn)行處理,例如在訪問(wèn)到函數(shù)聲明/定義類(lèi)型節(jié)點(diǎn)時(shí),會(huì)調(diào)用步驟1-1中實(shí)現(xiàn)的visitfunctiondecl重載函數(shù)僅獲得函數(shù)定義相關(guān)信息;clang編譯器每次構(gòu)造完抽象語(yǔ)法樹(shù)后都會(huì)調(diào)用該驅(qū)動(dòng)函數(shù),綜合步驟1和步驟2中的重載函數(shù),可以在每次ast構(gòu)造結(jié)束后都獲得相關(guān)源碼的函數(shù)調(diào)用關(guān)系圖。
圖4為接口函數(shù)調(diào)用點(diǎn)查找過(guò)程的原理圖,展示了本發(fā)明中接口函數(shù)調(diào)用點(diǎn)查找算法模塊的實(shí)現(xiàn)方法,具體步驟如下:
步驟1,從內(nèi)核鏡像vmlinux中整理出函數(shù)符號(hào)表和接口函數(shù)表,具體實(shí)現(xiàn)過(guò)程如下:
步驟1-1,通過(guò)nm命令從內(nèi)核鏡像vmlinux中獲得帶有位置信息的內(nèi)核符號(hào)表,并根據(jù)符號(hào)類(lèi)型篩選出函數(shù)符號(hào)信息和接口函數(shù)信息,其中將類(lèi)型為t或t的符號(hào)整理為函數(shù)符號(hào)信息,而將類(lèi)型為t的符號(hào)整理為接口函數(shù)信息;
步驟1-2,設(shè)計(jì)兩種哈希表,分別以函數(shù)名和函數(shù)地址為關(guān)鍵字;將步驟1-1得到的函數(shù)符號(hào)信息存入以函數(shù)名為關(guān)鍵字的哈希表中,并將該哈希表作為函數(shù)符號(hào)表;將步驟1-1得到的接口函數(shù)表按兩種格式分別存入以函數(shù)名為關(guān)鍵字的哈希表和已函數(shù)地址為關(guān)鍵字的哈希表中,這兩個(gè)哈希表都稱(chēng)為接口函數(shù)表。
步驟2,遍歷被隔離模塊的函數(shù)調(diào)用關(guān)系圖,對(duì)每個(gè)調(diào)用函數(shù)或被調(diào)用函數(shù)都在步驟1中的得到的函數(shù)符號(hào)表中搜索對(duì)應(yīng)的模塊信息,并將得到的模塊信息以字符串標(biāo)簽的形式打印到函數(shù)調(diào)用關(guān)系圖中的相應(yīng)位置;
步驟3,設(shè)計(jì)兩種接口函數(shù)調(diào)用點(diǎn)查找算法,分別提供按模塊查找和按函數(shù)查找接口函數(shù)調(diào)用點(diǎn)的功能;利用這兩個(gè)算法對(duì)步驟2中得到的帶有模塊標(biāo)簽的函數(shù)調(diào)用關(guān)系圖進(jìn)行分析,以得到被隔離模塊中所有調(diào)用其它模塊接口函數(shù)的位置:
步驟3-1,在按模塊查找接口函數(shù)調(diào)用點(diǎn)的算法中,遍歷帶模塊標(biāo)簽的函數(shù)關(guān)系調(diào)用圖,首先將第一個(gè)關(guān)鍵字(即調(diào)用函數(shù))作為當(dāng)前關(guān)鍵字函數(shù);接著遍歷當(dāng)前關(guān)鍵字函數(shù)對(duì)應(yīng)的值列表(即被調(diào)用函數(shù)列表),依次判斷列表中的被調(diào)用函數(shù)的定義是否在當(dāng)前模塊或頭文件中:若是,則繼續(xù)檢查下一個(gè)被調(diào)用函數(shù);否則,將當(dāng)前的調(diào)用函數(shù)和被調(diào)用函數(shù)組成二元組,保存在特定的哈希表中,以便后續(xù)打印結(jié)果。
步驟3-2,在按函數(shù)查找接口函數(shù)調(diào)用點(diǎn)的算法中,遍歷帶模塊標(biāo)簽的函數(shù)關(guān)系調(diào)用圖,首先將被查找函數(shù)作為當(dāng)前關(guān)鍵字函數(shù);接著深度優(yōu)先遍歷當(dāng)前關(guān)鍵字函數(shù)的第一層被調(diào)用函數(shù)列表,判斷列表中的被調(diào)用函數(shù)的定義是否在當(dāng)前模塊或頭文件中(為了提高效率,可以先判斷當(dāng)前的被調(diào)用函數(shù)是否已被檢查過(guò),并跳過(guò)那些已被檢查的函數(shù)):若是,則將該被調(diào)用函數(shù)作為當(dāng)前關(guān)鍵字函數(shù)按之前的方式繼續(xù)遞歸檢查;否則,將當(dāng)前關(guān)鍵字函數(shù)和該被調(diào)用函數(shù)組成的二元組作為接口函數(shù)調(diào)用點(diǎn)保存在特定的哈希表中,以便后續(xù)打印結(jié)果。
圖5為改造后的功能調(diào)用框架圖,展示了功能調(diào)用改造后被隔離模塊間的交互過(guò)程,具體實(shí)現(xiàn)過(guò)程如下:
步驟1,存根函數(shù)的執(zhí)行流程如下:
步驟1-1,生成并初始化消息塊,包括注冊(cè)回調(diào)函數(shù)、發(fā)送方當(dāng)前pcb以及接收方反饋消息所在的消息隊(duì)列號(hào);
步驟1-2,創(chuàng)建并初始化參數(shù)容器,并將其掛載到消息塊中;
步驟1-3,調(diào)用消息模塊提供的api函數(shù)msgsnd發(fā)送消息;
步驟1-4,在指定的消息隊(duì)列號(hào)上等待接收方的反饋消息;
步驟1-5,解析反饋消息中的返回值,并繼續(xù)執(zhí)行下一指令。
步驟2,回調(diào)函數(shù)的執(zhí)行流程如下:
步驟2-1,解析獲得的消息塊,并用其中的pcb指針偽裝自己的current,以此實(shí)現(xiàn)一致性;
步驟2-2,創(chuàng)建參數(shù)容器,并以此解析消息塊中的具體參數(shù);
步驟2-3,將具體參數(shù)傳入真正的工作函數(shù)(即原接口函數(shù)),并將返回值存入原消息塊的相關(guān)位置;
步驟2-4,調(diào)用消息模塊提供的api函數(shù)msgsnd,并將原消息塊(此時(shí)存有返回值)發(fā)送到消息塊中指定的消息隊(duì)列中。
圖6為進(jìn)程控制塊重定向的原理圖,展示了本發(fā)明是如何通過(guò)重定向current以解決數(shù)據(jù)一致性問(wèn)題的,具體實(shí)現(xiàn)過(guò)程如下:
步驟1,為被隔離模塊保存一個(gè)獨(dú)一無(wú)二而的全局變量temp,用來(lái)存儲(chǔ)內(nèi)核傳過(guò)來(lái)的pcb指針;
步驟2,根據(jù)需要重定義current,具體做法是通過(guò)get_current()判斷當(dāng)前進(jìn)程是被隔離模塊進(jìn)程還是內(nèi)核進(jìn)程,若是被隔離模塊進(jìn)程,則返回全局變量temp;若是內(nèi)核進(jìn)程,則直接返回get_current()的結(jié)果;
步驟3,被隔離模塊每次從內(nèi)核接收到新的消息塊時(shí),都用該消息塊中描述pcb的成員去更新其全局變量temp,以此達(dá)到實(shí)時(shí)性的目的。
綜上所述,本發(fā)明解決了原linux內(nèi)核的功能調(diào)用方式無(wú)法適用于基于內(nèi)存頁(yè)表不可見(jiàn)性的內(nèi)核模塊隔離方案這一問(wèn)題,依次通過(guò)提取函數(shù)調(diào)用關(guān)系圖、查找接口函數(shù)調(diào)用點(diǎn)、編寫(xiě)存根子模塊和回調(diào)子模塊、接口函數(shù)調(diào)用點(diǎn)源碼替換以及重定向進(jìn)程控制塊這五個(gè)步驟,將被隔離模塊間的功能調(diào)用方式由原來(lái)的宏內(nèi)核模式改為微內(nèi)核模式,以允許被隔離模塊依舊可以正常的訪問(wèn)內(nèi)核中其它模塊的代碼和數(shù)據(jù)。目前本發(fā)明已經(jīng)成功應(yīng)用于文件系統(tǒng)隔離和驅(qū)動(dòng)隔離。
本發(fā)明提供了一種針對(duì)linux內(nèi)核頁(yè)表隔離的功能調(diào)用改造方法,對(duì)本技術(shù)領(lǐng)域的普通技術(shù)人員來(lái)說(shuō),在不脫離本發(fā)明原理的前提下,還適用于若干場(chǎng)景,例如利用該方法對(duì)linux進(jìn)行微內(nèi)核化。這些應(yīng)用場(chǎng)景也應(yīng)視為本發(fā)明的保護(hù)范圍。