假設我們想由**段a轉移到**段b,運用乙個呼叫門g,呼叫門g中的目標選擇子指向**b的段。這裡有幾個要素:cpl、rpl、**b得dpl(dpl_b)、呼叫門g的dpl(dpl_g)。a訪問呼叫門g是,要求cpl和rpl都小於等於dpl_g。即cpl和rpl需要在更高的特權級上。
除了上面一步符合要求之外,系統還將比較cpl和dpl_b。如果一致**段的話,要求dpl_b<=cpl;如果非一致**段的話,call指令和jmp指令有所不同。call指令要求dpl_b<=cpl;在用jmp指令時,只能是dpl_b=cpl.
綜上所述,呼叫門特權規則如下圖:
通過呼叫門call指令,可以實現從低特權級到高特權級的轉移,無論目標**段是一致的還是非一致的。
在有特權級轉移時,堆疊也會隨之變化,見下圖
每個任務最多可能在4個特權級間轉移,所以每個任務實際需要4個堆疊。可是我們只有乙個ss和esp,在發生堆疊切換時,從**獲得其餘堆疊ss和esp呢?從tss(task-state stack)。32位tss如下圖所示:
tss包含多個字段,這裡只需要關注偏移4到偏移27的3個ss和3個esp。當發生堆疊切換時,記憶體的ss和esp就是從這裡取得的。比如我們當前所在的ring3,當轉移至ring1時,堆疊將被自動切換到由ss1和esp1指定的位置。由於只是外層到內層(低特權級到高特權級),切換時新堆疊會從tss中取得,所以tss中沒有位於最外層的ring3的堆疊資訊。
了解了堆疊問題,就可以屢清特權級轉移了。
呼叫門從外層到內層的轉移過程:
1、根據目標**段的dpl(新的cpl)從tss中選擇應該切換到哪個ss和esp
2、從tss中讀取新的ss和esp。在這過程中如果發現ss、esp或者tss界限錯誤都會導致tss異常(#ts)
3、對ss描述符進行檢查,如果發生錯誤,同樣產生#ts異常
4、暫時性儲存當前ss和esp值
5、載入新的ss和esp
6、將剛剛儲存起來的ss和esp的值壓入新棧
7、從呼叫者堆疊中獎引數複製到被呼叫者堆疊(新堆疊)中,複製引數的數目由呼叫門中param count一項來決定。如果param count是零的話,將不會複製引數。
8、將當前的cs和eip壓棧
9、載入呼叫門中指定的新的cs和eip,開始執行被呼叫過程。
第7步中,paramcount只有5位,最多只能複製31個引數。如果引數多於31,可以讓其中某個引數變成指向乙個資料結構的指標。
ret指令返回的步驟:
1、檢查儲存的cs中的rpl以判斷返回時是否要變換特權級。
2、載入被呼叫者堆疊上的cs和eip(此時會進行**段描述符和選擇子型別和特權級檢驗)
3、如果ret指令含有引數,則增加esp的值以跳過引數,然後esp將指向被儲存過的呼叫者ss和esp。注意,ret的引數必須對應呼叫門中的param count的值。
4、載入ss和esp,切換到呼叫者堆疊,被呼叫者的ss和esp被丟棄,這裡將會進行ss描述符、esp以及ss段描述符的檢驗。
5、如果ret指令含有引數,增加esp的值以跳過引數(此時已經在呼叫者堆疊中)
6、檢查ds、es、fs、gs的值,如果其中哪乙個暫存器指向的段的dpl小於cpl(此規則不適用於一致**段),那麼乙個空描述符會被載入到該暫存器。
下圖是返回的步驟:
綜上所述,使用呼叫門的過程實際分為兩個部分,一部分是從低特權級到高特權級,通過呼叫門call指令來實現;另一部分是從高特權級到低特權級,通過ret指令來實現。
特權級2 不通過呼叫門
特權級檢查的時間 在選擇子沒有被裝入cs之前進行檢查,如果檢查成功則將選擇子裝入cs暫存器。相應的rpl變為cpl。我覺得這個檢查的機制就像是資料庫的對內容的約束檢查,或者說更像是乙個before型別的觸發器。當cpl rpl dpl都通過檢查後,cpu將選擇子裝入相應的暫存器中。否則產生乙個通用保...
長呼叫與短呼叫 呼叫門
cs裡的是乙個段選擇子 1 拆分段選擇子,查gdt表 2 該段描述符為系統描述符,s位為0,type為1100,是乙個門描述符 dpl必須為3,不然該描述符的許可權檢查過不去 3 該描述符的16到31位為另外乙個段描述符的選擇子 決定是否提權 另外乙個段描述符 必須是 段 dpl決定是否提權 長呼叫...
呼叫門描述符
門描述符跟段描述符的結構不同。2.它定義了在指定 段例程的入口點 偏移 3.它指定了呼叫者嘗試去訪問例程所需要的特權級 dpl 這裡是訪問者所要具備的特權級 4.如果發生了棧切換,它指定了拷貝到新棧的可選引數的數量 5位最多32個 也就是說,在跳到r0執行相應例程的時候,特權級便了,使用的棧也會改變...