特权级和调用门

转载 2016年08月30日 22:54:22

在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,转移过程如下:

  1. 根据目标代码的DPL从TSS中选择应该切换至哪个ss和esp
  2. 从TSS中读取新的ss和esp
  3. 暂时性地保存当前的ss和esp的值
  4. 加载新的ss和esp
  5. 将刚刚保存起来的ss和esp的值压入新栈
  6. 将当前的cs和eip压栈
  7. 加载调用门中指定的新的cs和eip。

所以,从上面的过程中我们可以知道,在进行特权级转移时,首先根据目标代码的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

特权级3——调用门

调用门的作用 gate简单来说可以想象成政府为人民提供的一个政府诉求中心,它可以集中收集人民对政府的要求和投诉,然后把这些诉求发给相关的政府部门来处理。   门提供了受保护的间接调用,为任务内的...
  • bfboys
  • bfboys
  • 2016年09月01日 16:00
  • 249

保护模式编程——保护的详尽意义:通过调用门转移特权级

保护模式及其编程——保护机制 摘要:在汇编语言的编程和操作系统的编写过程中,我们经常能听说到“保护模式”这个名词。为什么要叫“保护模式”呢?保护 二字的含义何在?本文主要探讨,“保护模式”下面各种具体...
  • trochiluses
  • trochiluses
  • 2014年02月20日 22:14
  • 2989

32位保护模式学习小结(2)---任务的隔离和特权级保护

任务,任务的LDT和TSS 程序是记录在载体上的指令和数据,其正在执行中的一个副本,叫做任务(Task)。而用户程序就是任务,内核程序就是操作系统的缩影。LDT我们把所有的段描述符都放在GDT中。...
  • wrx1721267632
  • wrx1721267632
  • 2016年08月02日 23:05
  • 626

特权级3(调用门)

调用门的作用 gate简单来说可以想象成政府为人民提供的一个政府诉求中心,它可以集中收集人民对政府的要求和投诉,然后把这些诉求发给相关的政府部门来处理。   门提供了受保护的间接调用,为任务内的...
  • judyge
  • judyge
  • 2016年08月31日 09:47
  • 144

特权级2(不通过调用门)

特权级2——不通过调用门   特权级检查的时间 在选择子没有被装入CS之前进行检查,如果检查成功则将选择子装入CS寄存器。相应的RPL变为CPL。我觉得这个检查的机制就像是数据库的对内容的约束检查,或...
  • wswupeng
  • wswupeng
  • 2010年05月11日 20:59
  • 854

特权级2——不通过调用门

特权级检查的时间   在选择子没有被装入CS之前进行检查,如果检查成功则将选择子装入CS寄存器。相应的RPL变为CPL。我觉得这个检查的机制就像是数据库的对内容的约束检查,或者说更像是一个befo...
  • bfboys
  • bfboys
  • 2016年09月01日 15:59
  • 142

代码段间转移控制时的特权级检查(JMP/CALL)——《x86汇编语言:从实模式到保护模式》读书笔记28

代码段间转移控制时的特权级检查(JMP或者CALL指令)在保护模式下,JMP或CALL指令可以用以下四种方法之一来引用另外一个代码段: 1. 目标操作数含有目标代码段的段选择子和偏移 2. 目标操...
  • u013490896
  • u013490896
  • 2016年05月07日 10:21
  • 1367

调用门实战(2)----调用门特权级转移理论篇

 假设我们想由代码段A转移到代码段B,运用一个调用门G,调用门G中的目标选择子指向代码B的段。这里有几个要素:CPL、RPL、代码B得DPL(DPL_B)、调用门G的DPL(DPL_G)。A访问调用门...
  • kkk8000
  • kkk8000
  • 2010年11月20日 19:26
  • 857

任务门,调用门,中断门,陷阱门

每个任务有一个任务状态段TSS,用于保存任务的有关信息,在任务内变换特权级和任务切换时,要用到这些信息。为了控制任务内发生特权级变换的转移,为了控制任务切换,一般要通过控制门进行这些转移。本文将介绍任...
  • barech
  • barech
  • 2009年08月02日 12:43
  • 11147

调用门详解

说明:此文是我将以前的两篇博文(读书笔记28和29)中的部分内容综合而来,如遇重复,请您自行跳过。...
  • u013490896
  • u013490896
  • 2016年05月17日 21:39
  • 2753
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:特权级和调用门
举报原因:
原因补充:

(最多只允许输入30个字)