1. 程式人生 > >關於CPL、RPL、DPL生動形象地解釋

關於CPL、RPL、DPL生動形象地解釋

保護模式中最重要的一個思想就是通過分級把程式碼隔離了起來,不同的程式碼在不同的級別 ,使大多數情況下都只和同級程式碼發生關係。 Intel的80286以上的cpu可以識別4個特權級(或特權層),0級到3級。數值越大特權越小。一般用把系統核心放在0級,系統的其他服務程式位於1、2級,3級則是應用軟體。一般情況下程式碼都在自己的級別下做自己的工作,同一級別之間可以相互訪問,而一般是不允許不同級別的程式碼間隨意訪問的。但有時候不同級別的程式之間一定要訪問,比如系統的介面函式等,必須能夠使得應用程式能夠隨意呼叫。於是Intel將程式碼分為:

1.非一致碼:受到隔離的程式碼,只能在同一級別間相互訪問

2.一致碼:不受到隔離的就是,允許被同等級或低等級程式碼呼叫

 

至於這部分我們下回再詳細說,這裡主要搞清楚RPL、DPL、CPL之間的關係。

 

 

Intel設定DPL、RPL、CPL以實現分級和許可權檢查。

 

DPL:描述符特權(Descriptor Privilege Level)

儲存在描述符中的許可權位,用於描述程式碼的所屬的特權等級,也就是程式碼本身真正的特權級。一個程式可以使用多個段(Data,Code,Stack)也可以只用一個code段等。正常的情況下,當程式的環境建立好後,段描述符都不需要改變——當然DPL也不需要改變,因此每個段的DPL值是固定。

 

 

RPL:請求特權級RPL(Request Privilege Level)

RPL儲存在選擇子的最低兩位。 RPL說明的是程序對段訪問的請求許可權,意思是當前程序想要的請求許可權。RPL的值由程式設計師自己來自由的設定,並不一定RPL>=CPL,但是當RPL<CPL時,實際起作用的就是CPL了,因為訪問時的特權檢查是判斷:EPL=max(RPL,CPL)<=DPL是否成立,所以RPL可以看成是每次訪問時的附加限制,RPL=0時附加限制最小,RPL=3時附加限制最大。所以你不要想通過來隨便設定一個rpl來訪問一個比cpl更內層的段。

 

因為你不可能得到比自己更高的許可權,你申請的許可權一定要比你實際許可權低才能通過CPU的審查,才能對你放行。所以實際上RPL的作用是程式設計師可以把自己的程式降級執行——有些時候為了更好的安全性,程式可以在適當的時機把自身降低許可權(RPL設成更大的值)。

 

網上許多人都說在問rpl的作用,我也很暈。Intel的手冊中對RPL的作用只是這樣做的簡短解釋的:

TheRPL can be used to insure that privileged code does not access asegment on behalf of an application program unless the program itselfhas access privileges for that segment.

 

後來找到了一些資料對這段話進行了擴充和舉例,我才明白一些:

對於特權級高的程序RPL是作用是防止自己不小心訪問到一些資料段。比方說,如果程序A的CPL=0,它知道它的委託程序B的DPL=3,也知道資料段C的DPL=2,而這資料段是不能讓CPL>2的程序訪問的。

 

那麼如果你是程序A的程式設計師根本不需要RPL的幫助,也不會試圖讓程序A訪問資料段C的資料,因為這樣做只會浪費時間。當然如果你一定要訪問資料段C的資料然後把資料傳給委託程序B,這就是你的選擇,你真的可以這樣做,但後果自負。只是有時候要訪問的資料段我們不知道它的DPL是怎麼,也不知道能不能讓程序B訪問,其中的一個解決方法就是把委託程序B的DPL以RPL的方法告訴資料段C讓它決定接受或不接受。(我想應該是通過程式把B的DPL裝入到A的選擇子中,然後再由A去訪問資料段C)

CPL:當前任務特權(Current Privilege Level)

表示當前正在執行的程式碼所處的特權級。CPL儲存在CS中的最低兩位,是針對CS而言的。當選擇子成功裝入CS暫存器後,相應的選擇子中的RPL就變成了CPL。因為它的位置變了,已經被裝入到CS暫存器中了,所表達的意思也發生了變——原來的要求等級已經得到了滿足,就是當前自己的等級。

 

選擇子可以有許多個,因此RPL也就有許多個。而CPL就不同了,正在執行的程式碼在某一時刻就只有這個值唯一的代表程式的CPL.

 

另外特別要求CS與SS的特權級必須保持一致。對於裝入DS、ES、FS、GS的選擇子INTEL沒有給它們起什麼特殊的名稱,我也不知道應該叫它們什麼,也許可以仍然稱它為RPL。

 

 

 

應用RPL實現資料段的特權級保護的例項

 

計算機軟體一般由作業系統程式和應用程式組成。為了組建高可靠性的軟體系統,要求作業系統的資料不允許被應用程式改變,否則,應用程式會影響系統的安全執行,嚴重時導致系統崩潰瓦解。一個由作業系統程式與應用程式組成的軟體如圖1所示。在作業系統程式中有一MOVE過程把一個數據段中的資料塊寫到另一個數據段中,MOVE過程是通過引數傳入被呼叫的,即 MOVE(destination,source,count)。其中:source源資料塊的邏輯地址;destination 目標資料塊的邏輯地址;count 傳送的位元組數

 

   
   


 

資料塊的邏輯地址由資料段選擇字對應的資料段描述符和資料塊偏移量所描述。

 


MOVE過程是作業系統的程式,它可以合法地被作業系統中的其它過程呼叫,完成作業系統資料段中的資料塊移動和作業系統資料段與應用程式資料段中的資料塊移動。但是,若MOVE過程被應用程式呼叫,作業系統資料段的資料有可能失去保護作用。設應用程式的典型呼叫情形為:

 

①MOVE(資料塊A,資料塊1,count)

②MOVE(資料塊B,資料塊A,count)

③MOVE(資料塊2,資料塊1,count)

④MOVE(資料塊1,資料塊A,count)

 

情形①:應用程式通過MOVE過程得到作業系統資料塊的資訊;

情形②:應用程式利用MOVE過程完成應用程式資料塊之間的資料移動;

 

①、②這二種情形是合法的要求。

 

情形③:應用程式控制了作業系統的工作,沒有按作業系統的工作步驟,強行改變了資料塊2的內容;

情形④:應用程式將應用程式資料塊A的內容移動到作業系統資料塊1中,自行改變了資料塊1的內容;

 

在③、④這二種情形使作業系統的資料得不到核心保護,作業系統的資料受到了應用程式的侵犯。

 

 

針對上述的侵權示例,如何防止應用程式改變作業系統的資料,即情形①和②;並且,應用程式能通過呼叫作業系統程式中的MOVE過程合法地使用,即情形③和④;這是作業系統軟體設計中必須考慮的問題。

 

設呼叫MOVE過程的程式段Proc為:

 

……

 

LDS EAX,source ;DS:EAX=source源資料塊的邏輯地址

 

PUSH DS ;壓入source源資料塊的選擇字

 

PUSH EAX ;壓入source源資料塊的偏移量

 

LDS EAX,destination ;DS:EAX=destination目標資料塊的邏輯地址

 

PUSH DS ;壓入destination目標資料塊的選擇字

 

PUSH EAX ;壓入destination目標資料塊的偏移量

 

MOV ECX,count ;ECX=傳送的位元組數count

 

PUSH ECX ;壓入傳送的位元組數count

 

CALL MOVE ;呼叫MOVE過程,MOVE由呼叫門描述

 

……

 

如果Proc在作業系統程式中,無論source源資料塊和destination目標資料塊屬於作業系統或應用程式,都能合法的運作。

 

如果Proc在應用程式中,有可能產生情形③和④。例如,應用程式傳入的目標資料塊選擇字的RPL=0,就意味著應用程式要對作業系統的資料段進行非法寫入。為此,必須在MOVE過程中加以判斷,避免情形③和④的產生。

 


在MOVE過程中採用的處理方法是:目標資料塊選擇子的RPL應以主調程式的CPL為準。即採用ARPL指令改目標資料塊選擇子的RPL為主調程式的CPL(關於ARPL指令的使用說明見最後)。依據應用程式呼叫MOVE過程的堆疊,如圖2所示,在MOVE過程始部(開始)加入的指令為:

 

MOV AX,SS:[ESP+4] ;AX=CS主調程式的程式碼段選擇字

 

;其RPL欄位為主調程式的CPL

 

ARPL SS:[ESP+10],AX ;改目標資料塊選擇子的RPL為主調程式的CPL

 

MOV ES,SS:[ESP+10] ;ES=目標資料塊選擇子(其RPL欄位為主調程式 ;的CPL)

 

……

 

進行了上述處理以後,如果應用程式傳入的目標資料塊選擇字的RPL=0,ARPL把它修改為RPL=3,再傳送到ES段暫存器中,顯然不能滿足選擇字的裝載要求,即MAX(CPL,RPL)≤DPL,其中,MOVE過程的CPL=0;目標資料塊選擇字對應的資料段描述符中的DPL=0。CPU內部立即產生通用保護異常中斷進行處理。處理的結果通常為:終止當前的MOVE過程操作,返回應用程式;或終止應用程式的執行,返回作業系統。從而達到了保護目的。而情形①、②,應用程式完全可以合法實現。

 

 

 

[關於ARPL指令的使用說明]

 

調整申請特權級指令: ARPL OPRD1,OPRD2

其中,運算元OPRD1可以是16位通用暫存器或儲存單元,運算元OPRD2是16位通用暫存器。該指令把運算元OPRD1和OPRD2視為兩個選擇子,用OPRD2的RPL去檢查OPRD1的RPL。(選擇子OPRD1和OPRD2的RPL分別由它們的最低2個位規定。)

如果OPRD1的RPL值小於OPRD2的RPL值(OPRD1的特權級高於OPRD2),那麼零標誌ZF被置1,並把OPRD2的RPL值賦予OPRD1的RPL(使兩個運算元的最低2位相等);否則,零標誌ZF被清0。OPRD1和OPRD2都可為空選擇子。該指令隻影響ZF標誌。