特权级和调用门
在IA32的分段機制中,總共有4個特權級別,從高到低分別是0、1、2、3。處理器通過識別下面3中特權級進行特權級檢驗
1.CPL(Current Privilege Level)CPL是當前執行的程序或者任務的特權級,它被存儲在CS和SS的第0位和第1位上,通常情況下,CPL等于代碼所在的段的特權級,但是有一個例外是如果在遇到一致代碼段時,當處理器訪問一個與CPL特權級不同的代碼段時,CPL不會發生改變。
什么是一致碼段呢?它其實是由段描述符數據結構中的屬性字段決定的,“一致”的意思是當轉移的目標是一個特權級更高的代碼段時,當前的特權級會被延續下去,而向特權級更高的非一致代碼段轉移會引起常規保護錯誤,除非使用調用們或者任務門。而當目標代碼段的特權級低的話,無論它是不是一致代碼段,都不能通過call或者jmp轉移進去。另外所以的數據段都是非一致的,這意味著不可能被低特權級的代碼訪問到,然而,與代碼段不同的是,數據段可以被更高特權級的代碼段訪問,而不需要特定的門。
2.DPL(Descriptor Privilege Level) DPL表示段或者門的特權級,它被存儲在段描述符或者門描述符的DPL字段中,當當前代碼段試圖訪問一個段或者門時,DPL將會和CPL以及段或者門選擇自的RPL相比較。DPL的比較分下面5種情況:
- 數據段:DPL規定了可以訪問此段的最低特權級
- 非一致代碼段(不使用調用門情況下):DPL規定了訪問此段的特權級
- 調用門:DPL規定了當前執行的程序或者任務可以訪問此調用門的最低特權級(這個和數據段的規則是一致的)
- 一致代碼段和通過調用門訪問的非一致代碼段:DPL規定了可以訪問此段的最高特權級
- TSS:DPL規定了可以訪問此TSS的最低特權級
3.RPL(Requested Privilege Level) RPL是通過段選擇子的第0位和第1位表示出來的。處理器通過檢查RPL和CPL來確認一個訪問請求是否合法。
所以對數據段的訪問比較簡單,就是檢驗特權級,只要CPL和RPL都小于被訪問的數據段的DPL就可以了
對程序段的訪問比較復雜,程序從一個代碼轉移到另外一個代碼之前,目標代碼段的選擇子會被加載到cs中,作為加載的一部分,處理器將檢查描述符的界限、類型、特權級的內容。如果檢驗成功,cs將會被加載。
使用jmp或者call指令可以實現下列4種轉移:
- 目標操作數包含目標代碼段的段選擇子(直接轉移)
- 目標操作數指向一個包含目標代碼段選擇子的調用門描述符(間接轉移)
- 目標操作數指向一個包含目標代碼段選擇子的TSS(間接轉移)
- 目標操作數指向一個任務門,這個任務門指向一個包含目標代碼段選擇子的TSS(間接轉移)
調用門:什么是調用門,它也是一種描述符,它的結構定義如下:
; 門
; usage: Gate Selector, Offset, DCount, Attr
;??????? Selector:? dw
;??????? Offset:??? dd
;??????? DCount:??? db
;??????? Attr:????? db
%macro Gate 4
dw (%2 & 0FFFFh); 偏移 1(2 字節)
dw %1; 選擇子(2 字節)
dw (%3 & 1Fh) | ((%4 << 8) & 0FF00h) ; 屬性(2 字節)
dw ((%2 >> 16) & 0FFFFh); 偏移 2(2 字節)
%endmacro ; 共 8 字節
和段描述符的6個字節結構不一樣,門是由8字節構成,這個描述符也是放置在GDT,LDT或者IDT中以供調用。門描述符分為4種:
- 調用門
- 中斷門
- 陷阱門
- 任務門
門調用其實就是提供了一個入口地址,它可以實現的是不同特權級的代碼之間的轉移。下面介紹一下具體的過程:
假設我們想由代碼A轉移到代碼B,運用一個調用門G,即調用門G中的目標選擇子指向代碼B的段,我們涉及這么幾個要素:CPL、RPL、代碼B的DPL(DPL_B)和調用門的DPL(DPL_G)。根據門調用的規則,A要調用G,則A的CPL和RPL要小于DPL_G,另外還要比較CPL和DPL_B,如果是一致代碼段的話,要求DPL_B小于等于CPL,如果是非一致代碼段的話,call指令要求DPL_B小于等于CPL,jmp指令要求DPL_B=CPL。
這里我不是特別清楚,可能是如果沒有通過門調用,會直接比較RPL和DPL_B,因此門調用能夠實現從低特權級到高特權級的轉移。
TSS介紹:在進行call和jmp時候,必然要使用堆棧,然而由于不同的特權級會使用不同的堆棧,因此一個任務最多可能有4個堆棧,那么當轉移指令在不同特權級之間變化的時候,壓入堆棧的內容在另外一個特權級里面已經不是原來的堆棧了,對于這個問題,就引出了TSS(Task-State Stack)這個數據結構。這個數據結構中存在著ss2、esp2;ss1、esp1;ss0、esp0,轉移過程如下:
所以,從上面的過程中我們可以知道,在進行特權級轉移時,首先根據目標代碼的DPL從TSS中取得對應的ss和esp,然后加載新的ss和esp,也就是使用新的堆棧,并把老的堆棧的信息壓入新棧,以便返回時使用,然后再進行轉移
?
?
?
下面說明代碼段和數據段的訪問:
一、代碼段間跳轉
1、普通(直接)跳轉:
JMP Selector:0 或 CALL Selector:0
1)一致代碼段(JMP&CALL)
要求:CPL>=DPL,RPL不作檢查
特權變化:跳轉后程序CPL=跳轉前程序CPL
2)非一致代碼段(JMP&CALL)
要求:CPL=DPL & RPL<=DPL
特權變化:跳轉后程序CPL=目標代碼段DPL
2、通過調用門跳轉:
JMP 調用門Selector:0 或 CALL 調用門Selector:0 (注意:此時如果選擇子后面跟著32位偏移量也不會被CPU使用,因為調用門描述符已經記錄了目標代碼的偏移)
step1: 要求:指示調用門的選擇子的RPL<=門描述符DPL & 當前代碼段的CPL<=門描述符的DPL。
只有滿足以上條件時,CPU才會進一步從調用門描述符中讀取代碼段的選擇子或地址偏移。而從調用門中讀取代碼選擇子和地址偏移后,跟普通跳轉又站在同一起跑線上了。
唯一不同的是CPU會將目標代碼段RPL清0。此后需要分類討論,如下:
step2:
1)一致代碼段(JMP&CALL)? <------------------------------------------------------------------------------------------------------
要求:CPL>=DPL,RPL不作檢查(因為RPL總被清0)??????????????????????????????????????????????????????? |
特權變化:跳轉后程序CPL=跳轉前程序CPL??????????????????????????????????????????????????????????????????????? |
???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????? 比較
2)非一致代碼段(JMP)??????????????????????????????????????????????????????????????????????????????????????????????????????????????? |
要求:CPL=DPL,RPL不作檢查(因為RPL總被清0)????????????????????????????????????????????????????????? |
特權變化:跳轉后程序CPL=目標代碼段DPL??????????????????????????????????????????????????????????????????????? |
3)非一致代碼段(CALL)? <------------------------------------------------------------------------------------------------------------
要求:CPL>=DPL,RPL不作檢查(因為RPL總被清0)
特權變化:跳轉后程序CPL=目標代碼段DPL(CPL>DPL的情況下,特權級發生躍遷)
二、訪問數據段
數據段:特權級低->高:NO | 特權級高->低:YES | 特權級同級之間:YES
注意:
1、一致代碼段:無論那種方式跳轉到一致代碼段,CPL都不會改變(不變化為目標代碼段的DPL),也即加載目標代碼段選擇子時,只加載高14位,表示CPL的低2位保持不變。
因此,“一致”的意思就是——代碼段被調用執行時,不使用自己描述符的DPL,而采用調用這特權級,CS的低2位保持不變(與“調用者保持一致”)
2、非一致代碼段:無論采用哪種方式跳轉到非一致代碼段,CPL都發生變化,也即在加載目標代碼段選擇子時,將整個選擇子放入到CS中。
3、為了訪問調用門,調用者程序的特權級CPL必須小于或等于調用門的DPL。調用門段選擇符的RPL也要同調用CPL一樣遵守相同的規則,即RPL也必須小于或等于調用門的DPL
總結
- 上一篇: 第五章--加载内核Kernel.bin
- 下一篇: 调用门