RPL的故事 ——《x86汇编语言:从实模式到保护模式》读书笔记31
關(guān)于RPL(請求特權(quán)級),網(wǎng)上的資料不少,不過我認(rèn)為都沒有說明白。希望我可以把這個(gè)問題講清楚,如有紕繆,還請您不吝賜教。
要理解RPL,首先要明白訪問數(shù)據(jù)段時(shí)的特權(quán)級檢查規(guī)則。
1. 訪問數(shù)據(jù)段時(shí)的特權(quán)級檢查
為了訪問數(shù)據(jù)段,數(shù)據(jù)段的選擇子必須被加載進(jìn)段寄存器(DS,ES,FS,GS,SS)。在把一個(gè)段選擇子加載進(jìn)段寄存器之前,處理器會(huì)進(jìn)行特權(quán)級檢查(如下圖所示)。
在數(shù)值上必須滿足以下兩點(diǎn):
1. CPL<=數(shù)據(jù)段描述符的DPL
2. RPL<=數(shù)據(jù)段描述符的DPL
否則,會(huì)產(chǎn)生一個(gè)一般保護(hù)異常,且不加載段選擇子。
2. 為什么要引入RPL
2.1 概述
當(dāng)?shù)吞貦?quán)級的應(yīng)用程序使用call far指令通過調(diào)用門將控制轉(zhuǎn)移到較高特權(quán)級的非一致代碼段(例如操作系統(tǒng)提供的例程,假設(shè)其代碼段的DPL=0)時(shí),會(huì)改變當(dāng)前的特權(quán)級,而在目標(biāo)代碼段的特權(quán)級上執(zhí)行,對于本例來說CPL的數(shù)值就會(huì)變成操作系統(tǒng)例程段的DPL的數(shù)值,即0。如果沒有RPL,那么此時(shí)CPL權(quán)限是最高的,也就可以去訪問任何數(shù)據(jù),這就不安全了。所以引入RPL,讓它代表訪問權(quán)限,因此在檢查CPL的同時(shí),也會(huì)檢查RPL(正如上文第一節(jié)提到的規(guī)則)。一般來說如果RPL的數(shù)值比CPL大(權(quán)限比CPL的低),那么RPL會(huì)起決定性作用。
2.2 狡猾的應(yīng)用程序開發(fā)者
舉個(gè)例子,比如操作系統(tǒng)提供了一個(gè)調(diào)用門(這個(gè)門對應(yīng)的目標(biāo)代碼段的DPL為0),其功能是讀取硬盤的一個(gè)扇區(qū)到指定的內(nèi)存位置。這個(gè)調(diào)用門有3個(gè)參數(shù)(通過棧來傳遞),分別是邏輯扇區(qū)號、數(shù)據(jù)段選擇子和段內(nèi)的偏移。
假設(shè)有個(gè)應(yīng)用程序(運(yùn)行在特權(quán)級3)的開發(fā)者,通過苦心鉆研知道了操作系統(tǒng)數(shù)據(jù)段的選擇子(其指向的數(shù)據(jù)段的特權(quán)級為0),為了搞破壞,他把這個(gè)選擇子作為參數(shù)傳給了調(diào)用門。如果沒有RPL,那么訪問數(shù)據(jù)段的檢查規(guī)則就是“CPL<=數(shù)據(jù)段描述符的DPL”。當(dāng)通過調(diào)用門轉(zhuǎn)移后,CPL從3變成了目標(biāo)代碼段的特權(quán)級0,正好符合檢查規(guī)則,于是他的陰謀得逞了。
2.3 善變的CPL
仔細(xì)分析這個(gè)問題,根源在于CPL變了,搖身一變變成目標(biāo)代碼段的特權(quán)級了。所以引入RPL,讓RPL代表“真實(shí)”的CPL,并且再加上一條規(guī)則“RPL<=數(shù)據(jù)段描述符的DPL”,因?yàn)镽PL=3,所以檢查不會(huì)通過。
3. RPL的值是怎么來的
你可能會(huì)問,那RPL的值是怎么得來的?難道CPU可以智能識(shí)別出CPL變身了,然后自動(dòng)把CPL變身前的值傳遞給RPL?
不不不,CPU可沒有這么厲害。關(guān)于這個(gè)問題,我先告訴你一個(gè)好消息:RPL的值可以由當(dāng)前進(jìn)程隨便寫。就是上文圖中的那個(gè)黃色字段,你愛填多少填多少。
這下你樂了吧:)既然隨便寫,那我寫0好了。這樣一來,“RPL<=數(shù)據(jù)段描述符的DPL”總是成立的。
但是別高興,我還要宣布一條壞消息:操作系統(tǒng)會(huì)檢查RPL的值,如果你填寫的RPL在數(shù)值上小于CPL(調(diào)用者的特權(quán)級,而非目標(biāo)代碼段的特權(quán)級),那么操作系統(tǒng)會(huì)把RPL打回原形,強(qiáng)制它等于CPL。
4. ARPL指令
為了方便操作系統(tǒng)得到正確的RPL值,處理器提供了ARPL指令。該指令的作用是調(diào)整選擇子中RPL字段的值(Adjust RPL Field of Segment Selector),其格式為
arpl r/m16, r16該指令比較兩個(gè)選擇子的RPL字段。
目的操作數(shù)可以是一個(gè)通用寄存器(內(nèi)容是16位的段選擇子)或者一個(gè)指向16位單元的內(nèi)存地址(該16位單元存放的是段選擇子);
源操作數(shù)只能是一個(gè)通用寄存器(內(nèi)容是16位的段選擇子)。
該指令執(zhí)行時(shí),處理器檢查目的操作數(shù)的RPL字段,如果它在數(shù)值上小于源操作數(shù)的RPL字段,則設(shè)置ZF標(biāo)志,并修正目的操作數(shù)的RPL字段,使其等于源操作數(shù)的RPL字段值;否則,僅僅把ZF標(biāo)志清零,其他什么也不做。
ARPL是典型的操作系統(tǒng)指令,通常用于調(diào)整應(yīng)用程序傳遞給操作系統(tǒng)的段選擇子,使其RPL字段的值和應(yīng)用程序的特權(quán)級相匹配。
5. 火眼金睛的操作系統(tǒng)
結(jié)合上文2.2節(jié)的那個(gè)例子,配合下圖來說明。
為了防止惡意的數(shù)據(jù)訪問,操作系統(tǒng)應(yīng)該從當(dāng)前棧中取得用戶程序的代碼段選擇子(調(diào)用者代碼段寄存器CS的內(nèi)容,也就是下圖中的“原CS”)作為源操作數(shù),并且把作為參數(shù)傳遞進(jìn)來的數(shù)據(jù)段選擇子(下圖中的“參數(shù)2”)作為目的操作數(shù),來執(zhí)行ARPL指令,把數(shù)據(jù)段選擇子的RPL恢復(fù)到調(diào)用者的特權(quán)級別上。
一旦調(diào)整了請求特權(quán)級,那么當(dāng)前特權(quán)級CPL=0,RPL=3,數(shù)據(jù)段描述符的DPL=0,雖然符合“CPL<=數(shù)據(jù)段描述符的DPL”,但是不符合“RPL<=數(shù)據(jù)段描述符的DPL”,所以會(huì)禁止訪問,并引發(fā)異常。這樣一來,狡猾的應(yīng)用程序開發(fā)者的陰謀就不會(huì)得逞了。
總結(jié)
以上是生活随笔為你收集整理的RPL的故事 ——《x86汇编语言:从实模式到保护模式》读书笔记31的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python中星号数字乘字符串_Pyth
- 下一篇: 任务和特权级保护(二)——《x86汇编语