http://www.mcplive.cn/?controller=Article&id=5788&page=5特權層級
大部分的現代電腦體繫結構都有兩個或兩個以上的特權層級,用來分隔核心和應用軟體。以x86為例,為了得到更高的保護控制,在x86的保護模式下定義了當前特權層級(Current Previleged Level,簡稱CPL),一共有四個特級層次(0 to 3)被定義,我們一般稱之為Ring。Ring後面的數字越大特權越小,我們的作業系統一般都運行在Ring0上,而Ring1和2一般用來支援裝置驅動,Ring3上面跑的就是應用軟體了。而在現在的x86處理器中,64位架構已經非常普遍,64位CPU因為必須支援頁表模式,所以只有兩個特權層級,我們可以簡單理解為Ring0和Ring3(實際上另有明確定義),這種模型我們常稱為0/3模型。
系統中有一些關鍵操作指令只能在最高特權層級上執行,它們一般被稱為特權指令,特權指令僅僅在當前的特權層級為零時(CPL=0)才會執行。如果在非特權層級上試圖執行特權指令,將產生一個一般保護異常(這通常會產生一個應用程式錯誤),而非特權指令則可以在任何一個權限等級執行。
敏感指令中的漏網之魚
在虛擬化世界的VMM模型中,我們可以看到所有的客戶機作業系統都運行在非特權模式下,即非Ring0級。因為Guest OS已經不處在特權層級,所以存在一部分原本應該在特權層級執行但現在因為層級許可權不夠必須轉交VMM進行處理的指令,這部分指令就叫敏感指令。
x86的敏感指令中明顯有一部分漏網之魚
而根據Popek和Goldberg的定義,指令集支援虛擬化的前提是:所有敏感指令都是特權指令。很可惜x86指令集不能滿足這個要求,這是它和RISC架構相比的一個不足。
在IBM之類的RISC指令集方面,因為敏感指令全部是特權指令,所以敏感指令的執行都可以被VMM捕獲,而在x86方面,因為有一部分敏感指令不屬於特權指令,變成了非特權指令,而非特權指令在較低的特權層級上是可以直接執行的,也就是說VMM不會處理這些指令。這樣就勢必會帶來問題,試想一個不受虛擬化軟體層控制的指令卻工作在虛擬化層之上,這是怎樣一個情景?x86至少有十幾條敏感指令是不會引發異常的非特權指令,在IA-32指令集中,我們稱這些非特權層級的敏感指令為臨界指令,它們可以分成兩類:
敏感寄存器指令:它們讀取或者修改敏感寄存器和(或者)敏感記憶體資料區所存放的內容,比如時鐘寄存器、中斷寄存器。
1.SGDT、SIDT、SLDT
2.SMSW
3.PUSHF、POPF
保護系統指令:涉及儲存保護系統、記憶體或者地址定位系統。
1.LAR、LSL、VERR、VERW
2.POP
3.PUSH
4.CALL、JMP、INT n、RET
5.STR
6.MOV
臨界指令執行個體講解
我們用一個實際的例子來解釋x86指令集的虛擬化漏洞。SMSW指令(取機器狀態字的指令)是為了向下相容老式處理器,這個指令應該由作業系統完成,也就是說需要Ring0才可以,但很可惜它沒有被放在特權指令中。在虛擬化環境中,客戶機作業系統都工作在非特權層次上(一般為Ring1或者Ring3),前面我們講到非特權指令在較低特權層級時可以不被VMM捕獲而直接執行。
不同的特權層級滿足不同程式啟動並執行需求
客戶機作業系統在執行這個指令時,直接取到的是真實機器的值(假設取值1為保護模式,0為實模式),現在的VMM一般都工作在保護模式下,如果客戶機作業系統正好運行在實模式下,那麼問題就出來了,SMSW取到的值是1,表示系統運行在保護模式下,而不是真正的客戶機作業系統的實模式的傳回值0,這顯然是不正確的。