姜 博,張藝川,易 力,王 雷,姜 哲,鄒仕洪,3
1(北京航空航天大學 計算機學院 軟件開發(fā)環(huán)境國家重點實驗室,北京 100191)
2(元心信息科技集團有限公司,北京 100013)
3(北京郵電大學 網絡空間安全學院,北京 100876)
在微內核架構中,權能(Capability)是對進程所擁有的資源的一種描述,是一種無法偽造的權威令牌[1].權能的概念最早在1966年被提出,用來解決多用戶系統(tǒng)中的權限問題[2].在實際應用中,訪問控制列表(Access Control List)是一種廣泛使用的操作系統(tǒng)權限管理機制.Linux、Windows等經典操作系統(tǒng)與INTEGRITY[3]、PikeOS[4]等商用操作系統(tǒng)均使用該機制來實現(xiàn)權限控制,但該機制不能解決如混淆代理人(Confused deputy)[5]的權限泄露問題.相比于訪問控制列表,基于權能的系統(tǒng)在權限的劃分上粒度更細,每個進程在每個資源上擁有的權限都會通過權能詳細列出;此外,基于權能的系統(tǒng)在分配權能時遵循最小特權原則[6],從而使其得以解決上述問題.
一個標準的權能結構一般由兩個部分組成:該權能描述的資源的相關信息(如地址、類型等)和持有該權能的進程所獲得的對該資源的權限集合[7].為了保證每一個權能結構唯一不變地確定一個資源對象,該結構中的指向資源的指針被設計為自創(chuàng)建之后便無法修改.因此,在使用權能機制的操作系統(tǒng)中,進程在對資源執(zhí)行操作前必須首先獲得與其綁定的權能,并通過該權能提供的調用完成對資源的操作.通過這種方式,進程可以訪問的資源被限制在其權能空間中,不會超出其完成任務所必需的資源范圍,從而實現(xiàn)了權限細粒度化與特權最小化,響應了用戶對系統(tǒng)安全性的需求[8,9].
MOS是一個運行在ARMv8上的微內核操作系統(tǒng),它是北京航空航天大學操作系統(tǒng)教學科研團隊設計完成的,用于支撐北航操作系統(tǒng)實驗教學和實時領域的科研工作.MOS內核中提供了內存管理、進程調度、中斷處理、進程間通信以及一些基礎的系統(tǒng)調用,但是它仍然缺乏完善的權限管理機制.本工作針對此問題,首先對MOS系統(tǒng)中的內核對象進行分類處理,統(tǒng)計各個對象的類型,進而定義出各類型的對象所對應的權能類型;之后在內核中添加了權能的訪問權限體系與訪問控制功能,并實現(xiàn)了權能的創(chuàng)建、構造、復制、移動、刪除這五種基本操作;此外還在用戶態(tài)設計了一套進程間通信接口,并實現(xiàn)了一個進程服務器,以此為其他用戶態(tài)進程提供權能授予和撤銷的相關接口;最后基于實現(xiàn)好的權能機制,為用戶態(tài)應用程序提供了動態(tài)內存管理、內存共享、消息隊列等一系列標準C庫函數接口.
本章將介紹操作系統(tǒng)中典型的權能系統(tǒng)設計,以及權能系統(tǒng)在物聯(lián)網、區(qū)塊鏈等方向上的相關工作..
seL4[10]操作系統(tǒng)是L4微內核操作系統(tǒng)家族的一員,也是第一個經過了形式化驗證,從數學的角度驗證了其安全性的操作系統(tǒng),其在車載系統(tǒng)[11]、航空電子系統(tǒng)[12]、嵌入式[13]等方向有著良好的應用前景.微內核操作系統(tǒng)最初被提出,是為了解決宏內核操作系統(tǒng)的可靠性與穩(wěn)定性問題:宏內核操作系統(tǒng)將驅動等服務進程全部包括在內核中,使得系統(tǒng)內核容易崩潰;而在微內核系統(tǒng)中系統(tǒng)內核不會受到服務進程出錯的影響,從而在可靠性與穩(wěn)定性上優(yōu)于宏內核[14].但在早期的微內核(如Mach和MINIX)中,進程間通信機制遠遠慢于宏內核中的系統(tǒng)調用機制;當時,Unix系統(tǒng)中一次系統(tǒng)調用大約需要10μs,而微內核中的進程間通信則需要100μs[15].不過,隨著系統(tǒng)技術的進一步發(fā)展,通信開銷的問題在L4等微內核系統(tǒng)中得到了解決,而如何提升安全性成為了微內核的新的命題.作為第一個被形式化驗證的操作系統(tǒng),seL4使用了權能機制來實現(xiàn)其安全性.在seL4中,權能被分為通信節(jié)點、虛擬地址空間、物理頁幀等多種類型,每個用戶進程擁有其獨立的權能空間,規(guī)定了該進程能夠訪問的資源集合;seL4還為各應用程序提供了一套包括權能復制、移動、刪除等操作的權能操作接口[16].此外,seL4中所有的權能通過一個叫做權能派生樹(Capability Derivation Tree)的結構來進行追蹤:在啟動時,系統(tǒng)中僅存在一大塊無類型的權能;隨著權能的不斷派發(fā),最開始的無類型權能被不斷的切分、派生,并最終轉型為應用中的各類權能.
Barrelfish是一個面向異構與多核體系的操作系統(tǒng),由微軟劍橋研究院與蘇黎世理工大學共同提出[17].Barrelfish同樣采用了權能結構來保障操作系統(tǒng)的安全性.在Barrelfish中,權能的類型包括虛擬內存、未被映射的物理內存、內核中的數據控制塊等;與seL4不同,Barrelfish規(guī)定了一套樹狀的轉型規(guī)則,滿足該規(guī)則的兩類權能之間可以相互轉換.在權能的組織上,Barrelfish與seL4類似,采用了其將權能集合作為樹節(jié)點的機制,并在每個進程中保存其權能對應的樹的根節(jié)點地址.在權能的查找上,Barrelfish使用了兩級查找機制:樹節(jié)點中存放權能表的表項地址,表項中存放所對應的權能地址.在查找進程是否擁有對應權能時,操作系統(tǒng)需要從根節(jié)點向下查找,直至找到對應權能或確定查找失敗為止.
RedLeaf[18]是使用Rust語言編寫的、為了研究操作系統(tǒng)構成受語言特性的影響而搭建的操作系統(tǒng).該操作系統(tǒng)使用Rust本身的語言特性而非物理地址分配實現(xiàn)了進程之間的隔離;基于這種隔離方式,RedLeaf抽象出了域(domain)這一概念,并在域之間實現(xiàn)了信息隔離、錯誤隔離等安全措施.在Rust語言中,特征(trait)是對類型需要實現(xiàn)的一系列方法的描述.為了實現(xiàn)域之間的交互,RedLeaf將特征作為對域所提供接口的描述,并通過在不同域之間傳遞特征來實現(xiàn)域接口的暴露;而為了保證域之間交互的安全性,RedLeaf引入了權能系統(tǒng),并使用權能包裹在域之間傳遞的特征或其他對象,以權能的傳遞替代特征的傳遞.通過這種權能傳遞的方式,RedLeaf可以跳過內核的監(jiān)管并進一步提高跨域調用的效率,實現(xiàn)用戶進程直接調用驅動等高效操作.
除了在通用的操作系統(tǒng)中管理權限,權能系統(tǒng)還可以解決物聯(lián)網場景中的安全問題.在物聯(lián)網場景中,權限管理系統(tǒng)需要將不同架構、不同操作系統(tǒng)、不同職能的眾多物理設備組織起來,并對多種多樣的調用進行鑒權,傳統(tǒng)方法難以勝任;而權能系統(tǒng)的細粒度使其在物聯(lián)網領域具有較大的優(yōu)勢.因此,近年來有一些新型物聯(lián)網權限管理系統(tǒng)被提出[19,20],這些系統(tǒng)以權能的方式對不同物聯(lián)網設備的各類操作進行詳細地管理,在權限劃分粒度、執(zhí)行效率上要優(yōu)于傳統(tǒng)的權限管理系統(tǒng).
在分布式系統(tǒng)中,權能系統(tǒng)還可以與區(qū)塊鏈技術相結合,進一步提升其安全性.傳統(tǒng)的訪問控制系統(tǒng)一般為集中式,在分布式系統(tǒng)中遇到單點故障、數據泄露等問題;而區(qū)塊鏈由于天然具有分布的性質,可以解決集中式系統(tǒng)的問題,但其不能存儲大規(guī)模的數據.為了解決分布式系統(tǒng)中訪問控制的問題,一些工作致力于使用在系統(tǒng)中同時使用區(qū)塊鏈與權能[21,22],以充分利用權能系統(tǒng)的細粒度特性與區(qū)塊鏈的分布性、不可篡改性,從而在分布式系統(tǒng)中構建高效的訪問控制系統(tǒng).
此外,通過與RISC指令集的融合,權能系統(tǒng)也可以通過與傳統(tǒng)的頁表結構相結合,在硬件層面做到字節(jié)級別的內存保護,并實現(xiàn)錯誤隔離[23].由于這種權能體系結構是通過擴展指令集、增加協(xié)處理器等硬件層面的措施來完成的,其在提供全面、可量化的訪存保護的同時對大部分已有程序表現(xiàn)出良好的兼容性,并已出現(xiàn)眾多衍生工作[24,25].
由于系統(tǒng)結構的差異性,seL4與Barrelfish的權能設計方案較為重量級,RedLeaf對Rust語言特性高度依賴,使得已有的設計很難直接應用在MOS微內核操作系統(tǒng)上.本工作將借鑒上述操作系統(tǒng)權能設計的思想,針對MOS微內核操作系統(tǒng)設計輕量級的權能機制.
支持權能機制的MOS架構如圖1所示.為了在MOS中建立權能機制,本工作首先設計出MOS中可能出現(xiàn)的各種權能類型,并構建了權能基本操作與權能訪問控制兩個模塊.之后,為了將權能機制投入到實際應用中,本工作還基于權能機制重構了動態(tài)內存管理、共享內存等Libc庫模塊,并在用戶態(tài)設立了進程服務器與對應的IPC接口來滿足用戶程序對權能相關服務的需求.
圖1 包含權能機制的MOS架構圖Fig.1 MOS architecture with capability support
在權能系統(tǒng)的建設過程中,本工作首先對MOS操作系統(tǒng)所提供的內核資源進行了分類,并為每一種內核資源給出了與之相對應的權能類型;之后,本工作設計并提供了創(chuàng)建、鑄造、拷貝、移動、刪除5種調用作為權能的基本操作,并將MOS提供的調用轉化為對權能的基礎操作的調用,從而完成在權能系統(tǒng)下內核資源的訪問;最后,本工作在MOS的內核中加入了權能的尋址算法,并且在執(zhí)行操作前隱式地對權能所攜帶的權限位進行檢驗,從而實現(xiàn)了MOS上的權能訪問控制功能,同時又使得權能系統(tǒng)在內核中的復雜邏輯對應用程序而言完全透明.
3.1.1 權能的類型設計與結構組織
為了在MOS中實現(xiàn)多種類型的權能,本工作將權能結構定義為如圖2所示的cte結構體:表示權能類型的type字段,表示該權能所對應權限的rights字段,以及根據權能類型不同而實現(xiàn)不同的權能關聯(lián)對象信息的capability_u字段.
圖2 權能結構示意圖Fig.2 Structure of capability
本工作中設計的所有權能類型如表1所示.對于每一種權能類型,其對應的權能實現(xiàn)中都記錄了其描述的對象的地址、與之關聯(lián)的其他權能等信息,為權能的相關操作做好準備.此外,在所有權能中,CNode類型的權能較為特殊;這類權能與其對應的內核CNode資源一同完成系統(tǒng)中權能存儲結構的組織.而根據其對應的內核資源在存儲結構中的位置,CNode類型的權能又可以被分為L1CNode、L2CNode兩種.與Barrelfish的實現(xiàn)類似,MOS中的每個進程使用一棵深度為2的CNode樹來描述其擁有的權能;L1CNode,L2CNode分別對應該樹的根節(jié)點與次級節(jié)點.具體實現(xiàn)上,每個進程的進程控制塊中都會存放其內核中對應的L1CNode的地址,代表該進程的權能空間(Capability Space);內核中,每個CNode對象通過提供多個可以存放權能的槽(slot)來完成對權能的組織,L1CNode的槽中存放L2CNode類型的權能,L2CNode的槽中才存放進程的具體權能.需要注意的是,每個L2CNode中只能存放同種類型的權能;L2CNode允許存放的權能類型由其對應的槽的類型所決定.
表1 MOS中的權能類型Table 1 Capability types in MOS
3.1.2 權能基本操作的設計
作為一種無法偽造但可以交換的令牌,權能的任何操作必然需要內核的參與,否則無法保證其不可篡改性;除此之外,內核還必須為應用程序提供相對應的接口,使得應用程序之間可以進行權能的交換;最后,內核中還必須提供一組給予、收回權能的接口,來滿足安全系統(tǒng)的基本要求[26].據此,本工作共定義了以下幾種與權能相關的基本操作:
1)權能的創(chuàng)建
權能的創(chuàng)建算法接受要創(chuàng)建的權能類型T、權能的權限r,以及該權能存放的L2CNode的地址S.在創(chuàng)建之前,算法首先檢查地址S是否合法;在確認合法之后,算法會在S對應的L2CNode中分配一個空位存放新創(chuàng)建的權能,并初始化其權限、類型等信息,最后返回該權能的地址;若L2CNode中無法再分配空位,則直接返回.其具體步驟在算法1中給出.
算法1.權能創(chuàng)建算法
輸入:權能類型T,權能存放的L2CNode的地址 S,權能權限r
輸出:創(chuàng)建好的權能地址;若創(chuàng)建失敗輸出為空
1.if(S == NULL)∨(S.cap.u.type != L2CNode)then
2.returnNULL
3.endif
4. slot=alloc_slot(S)
5.ifslot == NULLthen
6.returnNULL
7.endif
8. struct cte* cap =(struct cte *)slot
9. 根據類型T初始化cap指向的對象信息
10. 將權能cap的權限初始化為r
11.returncap
2)權能的鑄造
權能的鑄造是指基于一個已有權能創(chuàng)建一個新的權能,且該新權能的權限范圍不超出原權能.本工作中的鑄造算法需要源權能空間地址S,原權能地址src_addr,目標權能空間D,目標權能地址dest_addr以及目標權能的權限r作為輸入.算法首先檢查輸入的參數,在S或D為空的情況下直接返回;之后,算法通過尋址找到源與目標權能地址所對應的源槽地址src_slot與目標槽地址dest_slot,并檢查其是否合法;此外,算法還檢查了目標權能的權限是否超出了原權能的權限.在檢查完畢之后,算法最后將源權能拷貝至dest_slot處,并設置其權限為r.其具體流程如算法2所示.
算法2.權能鑄造算法
輸入:源權能空間地址S,源權能地址 src_addr,目的權能空間地址D,目的權能地址 dest_addr,目的權能權限r
輸出:無
1.if(S == NULL)∨(D == NULL)then
2.return
3.endif
4. src_slot=mos_cap_resolve_addr(S,src_addr)
5. dest_slot=mos_cap_resolve_addr(D,dest_addr)
6.if(src_slot == NULL)∨(dest_slot != NULL)∨(r不是src_slot 中權能權限的子集)then
7.return
8.endif
9. 將src_slot中的權能拷貝至dest_slot
10. 將dest_slot中的權能權限設置為r
3)權能的復制
權能復制操作與權能的鑄造操作過程類似.權能復制函數以源權能空間地址S、源權能地址src_addr,目標權能空間D、目標權能地址dest_addr為輸入;該算法首先檢查S與D的合法性,再通過尋址算法找到權能地址所對應的源槽地址src_slot與目標槽地址dest_slot,同時檢查其是否合法.滿足以上條件后,算法將權能從src_slot拷貝至dest_slot,并保證拷貝前后的權能權限一致.
4)權能的移動
權能的移動過程需要將權能從一個槽移動到另一個槽中,并且保證移動后源槽中的權能被刪除.該算法的具體流程如與復制算法基本一致,但在完成拷貝之后需要將原位置的權能徹底刪除.
5)權能的刪除
權能刪除算法的詳細過程如算法3所示.該算法需要接受權能空間地址base與其中待刪除權能的地址addr作為輸入.算法首先對base地址進行檢驗,確認其合法后在其中查找權能地址addr所對應的槽地址.若成功查找到,則算法刪除槽中存放的權能;否則傳入的參數不合法,直接返回.
算法3.權能刪除算法
輸入:權能空間地址base,權能地址 addr.
輸出:無
1.ifbase == NULL then
2.return
3.endif
4. slot=mos_cap_resolve_addr(base,addr)
5.ifslot != NULLthen
6. 刪除slot中存放的權能
7.endif
3.1.3 權限的設計和訪問控制
MOS中,權能所持有的權限共分為5類;這些權限又可根據是否與對象有關分為兩種.其具體分類如表2所示.需要注意的是,其中的可復制權限表示可以對某個權能進行復制,而可深拷貝權限則表示可在復制權能的同時復制一個對象的副本.
表2 MOS中的權限類型Table 2 Authorities in MOS
根據權能的類型不同,權能可持有的權限類型也不同.在MOS中,只有Endpoint,Rgn,MQ 這3種權能能夠持有上述的權限;其具體對應關系如表3所示.
表3 權能與權限的對應關系Table 3 Relationship between capability and authorities
為了實現(xiàn)訪問控制功能,應用程序只有在向內核申請資源時才可設置對應權能的權限;任何通過復制、鑄造等方式從其他進程處得到的權限都不會超出原始范圍.此外,應用程序若需要訪問內核中的資源,則必須將之前獲得的相關權能一并傳入內核,使得內核得以通過權限位校驗來確認是否允許該進程訪問相應資源.在這種情景下,由于進程不能未經允許獲取其他進程資源的權能,從而無法訪問其他進程的資源,保證了系統(tǒng)的安全性.
在實現(xiàn)了基礎的權能操作之后,為了讓應用程序的所有操作經過權能系統(tǒng)的檢驗,MOS中提供給用戶進程的接口需要以權能調用的方式重新編寫.為了統(tǒng)一各類調用形式,本工作中所有的權能調用的形式為
本工作主要為用戶提供了3類經過重構的接口:動態(tài)內存管理、共享內存和消息隊列.
3.2.1 動態(tài)內存管理的設計
動態(tài)內存是隨進程在運行中向系統(tǒng)發(fā)出申請、釋放等請求而動態(tài)變化的內存區(qū)域.本工作中提供了4個有關動態(tài)內存管理的接口:malloc、realloc、calloc和free函數.
1)malloc
malloc函數是從系統(tǒng)中申請動態(tài)內存的關鍵函數;其從用戶進程處接受動態(tài)申請的內存大小為參數,并向操作系統(tǒng)申請對應大小的內存,并在成功時返回申請到的內存的起始地址.
在POSIX標準下,malloc函數需要使用brk系統(tǒng)調用進行實現(xiàn)[27],但這么做會產生兩個問題:1)容易因內存不斷回收釋放而產生內存碎片;2)不斷的通過系統(tǒng)調用進入內核態(tài)有可能造成效率的下降.因此,本工作選擇以內存池的方式對malloc函數進行了實現(xiàn),即在用戶態(tài)維護一個容納多塊內存的內存池,在程序申請內存時首先在內存池中進行查找,若存在符合要求的空閑內存則直接分配給該程序;否則再向內核申請一塊對應大小的內存分配給程序.而在程序進行內存釋放時,相關函數只需要在內存池中更改對應的標記,從而減少內存碎片并提高內存申請調用的速度.
基于內存池方案,并使用權能重構的malloc函數實現(xiàn)如圖3所示.malloc函數在被調用時首先會將請求的內存大小與頁面大小4KB進行對齊,計算出實際需要分配的內存大小;之后,該函數會遍歷內存池,尋找合適大小的未分配內存塊;若查找成功,則將該內存塊從內存池中移除并準備將其返回給應用程序.若內存池中不存在相匹配的內存塊,則malloc函數需要通過系統(tǒng)調用向內核申請對應大小的內存.
圖3 基于權能機制的malloc流程Fig.3 Workflow of malloc in capability mechanism
在系統(tǒng)調用過程中,內核首先需要為該段動態(tài)內存分配一塊Rgn類型的權能,并將該權能加入調用進程的權能空間中;之后,內核還需要根據內存大小申請一定數量的Page類型的權能,并同樣加入權能空間中;最后,內核將分配的物理頁加入頁表并映射到用戶空間,同時上移brk指針并返回.此外,系統(tǒng)調用后,用戶態(tài)程序也必須上移其brk指針.
在將分配好的內存返回之前,malloc函數還會檢查堆頂對應的內存塊是否空閑.若該內存塊空閑,則malloc函數會通過系統(tǒng)調用進入內核態(tài),在內核態(tài)中完成Rgn、Page兩種權能的刪除、物理內存的釋放以及brk指針的下移,來完成該部分內存的釋放工作.
2)free
free函數在動態(tài)內存管理系統(tǒng)中負責對動態(tài)申請內存的釋放.該函數接受一個指針為參數,并嘗試釋放該指針所指向的內存區(qū)域.
由于使用了內存池機制,free函數的實現(xiàn)相對簡單.該函數會首先對傳入的指針進行判斷,在確認該指針指向一塊動態(tài)分配內存之后,該函數會去查找對應的動態(tài)內存,將其狀態(tài)標記為空閑,并加入內存池的空閑鏈表中.
3)calloc
calloc函數接受兩個參數:元素個數nelem與元素大小elsize,并向系統(tǒng)申請一塊nelem×elsize大小的內存,并保證該塊內存已被初始化為0.
在MOS中,calloc函數的實現(xiàn)使用了malloc函數;首先根據參數計算申請的空間大小,將其傳入malloc函數,并將malloc函數返回的空間清零,最后返還給用戶程序.
4)realloc
realloc函數接受動態(tài)內存指針ptr與新的內存大小size,嘗試將ptr指針所指的動態(tài)內存的大小更改至size,并返回指向更改后的動態(tài)內存的指針.
由于邏輯相似性,realloc函數的實現(xiàn)同樣使用了malloc函數.realloc函數首先對傳入的新內存大小與原有內存大小進行比較,若后者小于等于前者,則不做任何修改,直接返回原指針;若后者大于前者,則需要調用malloc函數分配一塊新的內存,并將舊的內存中的內容拷貝過去,最后調用free函數釋放舊內存.
3.2.2 共享內存的設計
共享內存一般指多個進程在系統(tǒng)的支持下將不同虛地址空間中的地址映射到同一物理頁上,從而使得多個進程能夠訪問同一內容.由于其讀寫不需要系統(tǒng)內核的額外操作,共享內存的效率要高于管道、消息隊列等通信工具,是一種高效的進程間通信方式.
在MOS中,共享內存的實現(xiàn)主要基于兩個結構體:內核態(tài)共享內存信息結構體kshm與用戶態(tài)基本信息結構體shm.kshm結構體中保存了該結構體對應的共享內存的大小、使用該共享內存的進程數,以及該共享內存的權能等信息;而shm結構體中保存了共享內存基址、共享內存大小等基礎信息.之所以在用戶態(tài)維護記錄了共享內存基本信息的shm結構體,是為了相關函數能夠在內存分配的過程中在用戶態(tài)同步更新brk指針,以防止動態(tài)分配內存機制與共享內存分配機制之間發(fā)生沖突.
MOS共提供了3個共享內存操作函數:shmget,shmat和shmdt.
1)shmget
shmget調用用來根據約定好的索引值獲取相對應的共享內存的標識符.該函數接受3個參數:約定的共享內存結構體索引值key,共享內存大小size和標記位shmflg.
shmget函數首先會在用戶態(tài)根據索引值key查詢共享內存記錄;若該key在用戶態(tài)有對應記錄,則返回該記錄;若不存在對應記錄,則將其傳入內核進行進一步查詢.如果在內核中也查詢不到對應的記錄,程序會在內核中新建一個kshm結構體,使用size與shmflg對其各個字段進行初始化,并將其權能指針rgn_cte字段置NULL;返回到用戶態(tài)后,函數會將信息同步到對應的shm結構體中,并最終返回其標識符.
2)shmat
shmat函數用來將指定的共享內存映射到傳入的虛擬地址上,從而使得共享內存可以被程序直接使用.
shmat函數接受共享內存標識符shmid,目標虛擬地址shmaddr和標記位shmflg,并返回映射后的共享內存起始地址.接受參數后,函數首先檢查shmaddr對應的共享內存是否已經被綁定;若已被綁定則直接返回其對應的地址.否則,shmat會通過系統(tǒng)調用進入內核態(tài),并建立類型為Rgn的權能r供進程使用.在此之后,內核態(tài)程序會找出shmid對應的kshm結構體t并檢測是否有其他進程已經映射了該共享內存:若沒有進程映射過,內核需要申請對應的Page類型的權能,完成頁表映射,并將該權能寫入權能空間,最終將權能r保存到t中;否則只需要查找結構體t中的權能數組,映射t中的虛擬地址與該權能所對應的物理地址,再將r寫入t中即可.完成以上操作后,程序返回用戶態(tài),在shm結構體中進行相應的記錄,最后返回起始地址.
3)shmdt
shmdt函數負責無效化通過shmat函數與進程綁定的共享內存.區(qū)別于其他系統(tǒng),MOS的shmat函數中涉及到了權能的創(chuàng)建;因此在shmdt中這些權能需要被正確地銷毀.
shmdt函數接受待無效化的共享內存地址addr作為參數.shmdt首先檢驗addr是否存在,之后將其通過系統(tǒng)調用傳入內核.在內核中,程序先通過addr查找權能空間中的對應權能;再在kshm結構體中查找包含該全能的記錄.若查找成功,則將kshm結構體中的權能銷毀,取消頁表映射并返回用戶態(tài);用戶態(tài)程序再完成用戶態(tài)的清理工作,最后返回應用程序.若上述查找過程失敗,則說明傳入的地址無效或者權能無效,程序直接返回.
3.2.3 消息隊列的設計
除去共享內存外,消息隊列也是一種常見的進程間通信手段.消息隊列是一種可在進程間共享的公共資源,不同的進程可以打開同一消息隊列并接收或發(fā)送消息,從而達到通信的目的.在MOS中,消息隊列被設計為一種獨立于所有進程的內核對象,并通過MQ類型的權能進行管理.除了全能之外,MOS中與消息隊列有關的結構還有3個:消息隊列結構體kmq_header(存放使用標識、消息隊列索引、權能指針等),消息隊列屬性結構體kmq_attr(存放最大消息數、消息大小等)和消息隊列節(jié)點結構體kmq_node(存放消息、消息的優(yōu)先級等).其具體組織結構如圖4所示.
圖4 消息隊列結構示意圖Fig.4 Structure of message queue
修改后的MOS提供了一套完整的基于權能的消息隊列接口,包括mq_open,mq_close,mq_unlink,mq_receive,mq_send等眾多函數.以下對消息隊列的主要功能所設計的函數進行介紹.
1)消息隊列的獲取
用戶程序如果想要新建或者打開消息隊列資源,則需要調用mq_open接口.在MOS中,mq_open函數被設計為只接受3個參數:消息隊列的鍵值key,標志位oflag,以及消息隊列的屬性attr(僅在新建隊列時有效).
被調用時,mq_open函數首先根據傳入的key進行查找,若成功找到則增加該消息隊列的計數器并返回;若未能找到對應消息隊列,則需要根據oflag與attr新建一個MQ類型的權能與kmq_header結構體,將其與key互相關聯(lián)并返回.
2)消息隊列的銷毀
MOS中,與消息隊列銷毀相關的接口主要有兩個:mq_close和mq_unlink.其中前者負責關閉消息隊列,后者則負責銷毀無用的消息隊列.
mq_close函數接受一個消息隊列描述符作為參數.該函數會根據描述符查詢到消息隊列的信息,并檢查當前消息隊列打開數是否為1;若為1,則調用mq_unlink函數將其刪除;否則將其打開計數器減一并返回.
mq_unlink同樣接受一個消息隊列描述符作為參數.查找到消息隊列后,如果該消息隊列打開數不為1,則直接返回;否則,該函數會釋放該消息隊列資源以及該消息隊列中所含的所有消息節(jié)點資源,再從調用進程的權能空間中刪除對應的消息隊列權能,最終返回.
3)消息的發(fā)送與接收
消息隊列中消息的發(fā)送與接收分別依賴于兩個接口:mq_send與mq_receive.
mq_send接口接受一個消息隊列描述符,一條消息以及消息的優(yōu)先級;該函數在調用時首先會通過傳入的消息隊列描述符獲取對應的權能,并檢查進程是否具有可寫權限;確認寫入操作合法之后,該函數還會對消息的合法性進行校驗;通過所有檢驗之后,函數在內核中新建一個消息節(jié)點,將其加入消息隊列并返回.
mq_receive接口則主要接受一個消息隊列描述符,以及消息存放位置等其他信息;與mq_send類似,該函數也會首先獲取權能并檢查寫權限,并根據消息隊列信息檢查參數的合法性;在確認合法之后,該函數會遍歷消息隊列節(jié)點以找到優(yōu)先級最高的消息,將該消息以及相關信息一并返回.
MOS是一個微內核系統(tǒng);這使得MOS的內核中只包括最基礎的頁表映射、進程管理等功能,而其他大部分的功能的實現(xiàn)均依賴于用戶態(tài)程序.因此,MOS的用戶態(tài)中有一些進程需要為其他用戶進程提供服務,從而實現(xiàn)操作系統(tǒng)的全部功能;這些進程被稱為進程服務器.為了充分利用微內核結構的優(yōu)勢,同時為用戶態(tài)進程提供與權能相關的一眾接口,本工作為MOS中添加了一套原生的IPC機制,并基于該IPC機制設計了一個處理權能相關調用的進程服務器.
為了存放通信的內容,本工作在進程控制塊中加入了包括msg與caps兩個字段的ipc_buffer結構,其中msg數組存放IPC傳遞的參數,而caps數組則負責傳遞權能指針;用戶態(tài)程序可通過系統(tǒng)調用來獲取本結構中的信息.
在上述結構的基礎上,本工作設計了如表4所示的一套接口,包括了測試連接、監(jiān)聽、請求發(fā)送等接口,以此來實現(xiàn)進程服務器的全部功能.
表4 MOS中的進程服務器接口Table 4 Server interfaces in MOS
為了實現(xiàn)消息的發(fā)送與接收,MOS系統(tǒng)中的用戶進程通過Endpoint資源來記錄其發(fā)送或接收的請求;同時,內核中設計了全局的發(fā)送Endpoint鏈表與接收Endpoint鏈表,用來存放因IPC發(fā)送或接收而被阻塞的進程所提交的Endpoint.當用戶進程進行發(fā)送或接收時,若對方尚未準備好,則用戶進程的Endpoint會被保存到列表中,同時用戶進程被阻塞;但為了保證進程服務器能夠對多個進程進行正常服務,在進程服務器進行接收操作但沒有進程向其發(fā)送請求時,服務器會讓出時間片而非被阻塞.
用戶程序向進程服務器發(fā)送請求的詳細過程如圖5所示.應用程序首先需要向內核申請Endpoint;在得到該Endpoint對應的權能之后,應用程序通過系統(tǒng)調用修改自身的ipc_buffer,并先后調用send與recv來向進程服務器發(fā)送請求并得到請求結果.在內核中,send與recv兩次調用所提供的Endpoint會被分別加入發(fā)送鏈表與接收鏈表,同時用戶程序被阻塞,直至進程服務器完成該請求的相應.當進程服務器發(fā)現(xiàn)該請求后,對應的Endpoint會被從鏈表中移除;服務器進程根據Endpoint信息通過系統(tǒng)調用獲得用戶程序在ipc_buffer中儲存的調用參數,根據調用信息進行處理之后將結果放入自身的ipc_buffer中,通過send調用返回給用戶程序.
圖5 IPC請求流程示意圖Fig.5 Sequence diagram of IPC request
本工作針對實現(xiàn)了權能機制的MOS操作系統(tǒng),從權能系統(tǒng)的安全性與權能系統(tǒng)的效率兩方面對其進行了評估.
該本工作的試驗環(huán)境為使用Qemu仿真器模擬的ARMv8架構環(huán)境;該Qemu仿真器運行在Ubuntu操作系統(tǒng)中.作為試驗對象的MOS系統(tǒng)使用aarch64-elf-gcc進行編譯.其具體參數如表5所示.
表5 實驗環(huán)境Table 5 Experiment environment
4.2.1 權能的共享與撤銷
算法4.權能共享方測試樣例
輸入:無
輸出:無
1. cap=vka_alloc_rgn(size)//初始化權能
2. new_cap=cl_sendcap_rgn(0x1111,cap,0)//分配權能
3. cl_revoke_rgn(new_cap)//釋放權能
4. mos_yield()
5. new_cap=cl_sendcap_rgn(0x2222,cap,CAP_RW)
6. cl_revoke_rgn(new_cap)
7. mos_yield()
8. new_cap=cl_sendcap_rgn(0x3333,cap,CAP_COPY)
9. cl_revoke_rgn(new_cap)
10. mos_yield()
11. new_cap=cl_sendcap_rgn(0x4444,cap,CAP_DEEPCOPY)
12. cl_revoke_rgn(new_cap)
算法5.權能接收方測試樣例
輸入:無
輸出:無
1. cap=cl_recvcap_rgn(0x1111)//接收分享權能
2. addr=mos_rgn_map(cap)//讀寫測試
3. mos_yield()
4. cap=cl_recvcap_rgn(0x2222)
5. addr=mos_rgn_map(cap)
6. mos_yield()
7. addr=mos_rgn_map(cap)
8. mos_yield()
9. cap=cl_recvcap_rgn(0x3333)
10. slot=mos_cnode_allocslot(disp,SLOT_RGN)
11. //拷貝測試
copy_cap=mos_cnode_copy(cap,SLOT_RGN,slot)
12. mos_yield()
13. slot=mos_cnode_allocslot(disp,SLOT_RGN)
14. copy_cap=mos_cnode_copy(cap,SLOT_RGN,slot)
15. mos_yield()
16. cap=cl_recvcap_rgn(0x4444)
17. slot=mos_cnode_allocslot(disp,SLOT_RGN)
18. //深拷貝測試
copy_cap=mos_cnode_deepcopy(cap,SLOT_RGN,slot)
19. mos_yield()
20. slot=mos_cnode_allocslot(disp,SLOT_RGN)
21. copy_cap=mos_cnode_deepcopy(cap,SLOT_RGN,slot)
算法4與算法5分別展示了本實驗為驗證權能系統(tǒng)有效性而編寫的兩段測試代碼.在實驗過程中,這兩段代碼分別運行在兩個用戶進程中;其中共享方代碼負責向內核申請創(chuàng)建Rgn類型的權能,其先后將無權限、可讀寫、可拷貝、可深拷貝四種權限不同的權能分享給另一個進程,并在完成對應測試后撤銷該權能;而接收方則負責不斷地接收分享的權能,并在權能撤銷前與撤銷后不斷的嘗試使用權能進行讀寫、拷貝、深拷貝操作,以測試權能系統(tǒng)的有效性.
實驗得到的結果如表6所示.在讀寫測試中,接收方只有在擁有讀寫權能的前提下才能夠進行讀寫操作;而在拷貝操作測試中只有接收方進程的權能被撤銷之前才能進行對應操作,符合預期.
表6 測試結果Table 6 Test result
4.2.2 權能系統(tǒng)的性能測試
本工作在MOS系統(tǒng)中共實現(xiàn)了Page、CNode、Endpoint、Pcb、Rgn、MQ 6大類提供具體調用的權能,不同的權能類型對應的調用種類也不盡相同;本節(jié)實驗借助ARMv8中全局系統(tǒng)計數器[28],在函數的入口與出口分別全局系統(tǒng)計數器中的值進行讀取,從而測量MOS中實現(xiàn)的各類權能調用的性能.
Page,Endpoint,Rgn 3種權能的調用周期數如圖6所示;CNode,Pcb,MQ 3種權能的調用周期數如圖7所示.在6類權能調用中,對應進程控制塊的Pcb與對應權能組織結構的CNode兩類權能調用相比之下較為基礎,因而消耗周期較少;而涉及內存管理機制的Rgn類型權能調用需要維護內存結構,其內部邏輯較為復雜,因而所消耗周期最多.
圖6 Page,Endpoint,Rgn類型權能調用開銷Fig.6 Overhead of calls on Page,Endpoint and Rgn Capabilities
圖7 CNode,Pcb,MQ類型權能調用開銷Fig.7 Overhead of calls on CNode,Pcb and MQ capabilities
從總體來看,大部分的權能調用的時鐘周期數都在7500以下,而頁表、進程控制塊等底層調用的時鐘周期數基本在5000以下,相對較快;Rgn類權能調用雖然經過一定的優(yōu)化,但在所有調用中開銷最高;此外,Endpoint類調用中的endpoint_send函數的消耗周期數均明顯高于同類其他調用,這是因為這該函數流程中進行了較多的系統(tǒng)調用,在基礎功能之外增加了一定的周期消耗.
本工作在ARMv8的多核環(huán)境下,在微內核操作系統(tǒng)MOS上設計并實現(xiàn)了基于權能的安全系統(tǒng).本工作首先對MOS的內核對象進行了分類,并根據各類權能的具體作用設計了其對應的權能調用與權能權限;之后,本工作通過實現(xiàn)權能的創(chuàng)建、鑄造、復制、移動、刪除5種基本操作與尋址算法,建立起了基礎的權能系統(tǒng);此外,本工作對一部分的Libc接口基于權能體系進行了重寫,將用戶程序的相關操作置于權能系統(tǒng)監(jiān)督之下;最后,本工作還在MOS中設計了進程服務器,使得應用程序可以通過一套IPC接口來獲得權能的相關服務.完成設計之后,本工作驗證了權能系統(tǒng)維護系統(tǒng)安全的有效性,并對與權能相關的一系列操作的性能進行了測試與分析.