现在的位置: 首页 > 综合 > 正文

80×86保护模式下特权级转移

2012年12月10日 ⁄ 综合 ⁄ 共 2632字 ⁄ 字号 评论关闭

本文转载自http://xorrlei.blog.163.com/blog/static/163083449201131005615360/

80386搞的这个保护模式,最大的特点就是加入了安全检查,不再像实模式下那样,程序代码可以随意jmp,随意call了,受到了特权级的约束,关于特权级的概念我看无数的资料,各种大牛的解释,反复理解了好多次,这回我要再次整理一下。

CPL:当前CPU正在处理的代码段的特权级,存放在当前cs寄存器和ss寄存器的低2位;

DPL:要跳转过去的目标代码段的特权级,规定了能访问该段的特权级的标准,存放在该段的段描述中;

RPL:请求特权级,是判断一个跳转是不是合法的第二个标准,也是必须的要有的,下文详细解释,存放在目标段选择子中的低2位;

数据段堆栈段:访问这两个段的判断,比较简单,只要当前正在处理的代码段的CPL和RPL特权级都高于目标数据段或目标堆栈段的特权级就可以了,没什么好讲的。

一致代码段:可以理解成内核中的代码,但是属于内核中受保护级别比较低的那些代码,是内核专门提供给用户程序访问和调用的代码,它虽然是OS内核中的代码,特权级高,但允许被低特权级的用户代码访问。不过仅仅是被访问,当前的CPL还是用户代码段的CPL,不要期望内核代码的CPL,哈哈。

非一致代码段:这个就是普通用户程序中定义的段,section/segment等,它只允许同特权级的代码相互跳转。即用户代码只能跳转到用户代码,内核代码也只能跳转到内核代码。不要以为内核代码可以访问用户代码和用户数据,这样就很容易被捣蛋的人利用,使内核执行坏蛋写的恶心代码,导致内核崩溃。


================================================================================
                                下面详细解答一些我在学习时遇到的问题
================================================================================
1.有CPL和DPL进行判断不就可以了吗?为什么还需要一个RPL呢?
     因为当低权限的用户代码去调用高权限的OS内核代码来访问一个目标段时,由于CPU执行的是OS内核代码,所以CPL变成了操作系统的CPL,如果没有RPL,那么此时CPL权限比任何用户代码的权限都高,也就可以去访问任何数据,这就不安全了。所以引入RPL,让它去代表访问权限,因此在检查CPL的同时,也会检查RPL.一般来说如果RPL的数字比CPL大(权限比CPL的低),那么RPL会起决定性作用。

2.代码跳转有几种方式都是用什么指令?
      代码跳转大概可以分为2类,一类是直接跳转或者叫普通跳转,一类是通过门描述符来跳转。用jmp和call可以实现跳转

3.什么是跳转什么是访问?
      跳转特指去执行目标代码段的代码去了,除了进行特权级检查判断是否合法外,还会改变CPL
      访问只是指去数据段或者堆栈段取数据,还是执行当前的代码,只进行特权级检测,不改变CPL

4.直接跳转的特性
      直接跳转不发生特权级的跃迁,即不改变CPL,具体如下:

代码段 要求 特权变化
一致代码段 CPL >= DPL ,RPL不检查,也说是一致代码段描述符中的DPL规定可以转移到一致的代码段的最内层特权级(3级可以转移到0级,而0级只能转移到0级)。一致代码段描述符内DPL的这种解释,正好与正常的DPL的解释相反。这是为了提供对应用程序的共享支持,而不要求改变特权级。 转跳后程序的CPL = 转跳前程序的CPL
非一致代码段 CPL = DPL & RPL<= DPL 转跳后程序的CPL = 转跳前程序的CPL


5.利用门描述符跳转的特性
     这种方式,可以改变CPL。通过门描述符和call指令,可以实现从低特权级到高特权级的转移,具体如下:

代码段 要求 特权变化
一致代码段 CPL >= DPL ,RPL不检查 因为RPL被清0,所以事实上永远满足RPL <= DPL,这一点与普通跳转一致,适用于JMP和CALL。
转跳后程序的CPL = 转跳前程序的CPL,因此特权级没有发生跃迁。
非一致代码段(JMP) CPL = DPL (RPL被清0,不检查)
,若不满足要求则程序引起异常。
转跳后程序的CPL = DPL,
因为前提是CPL=DPL,所以转跳后程序的CPL = DPL不会改变CPL的值,特权级也没有发生变化。如果访问时不满足前提CPL=DPL,则引发异常。
非一致代码段(CALL) CPL >= DPL(RPL被清0,不检查),若不满足要求则程序引起异常。 转跳后程序的CPL = DPL,
当条件CPL=DPL时,程序跳转后CPL=DPL,特权级不发生跃迁;当CPL>DPL时,程序跳转后CPL=DPL,特权级发生跃 迁,这是我们当目前位置唯一见到的使程序当前执行优先级(CPL)发生变化的跳转方法,即用CALL指令+调用门方式跳转,且目标代码段是非一致代码段。



      当 段间转移指令JMP和段间转移指令CALL后跟着的目标段选择子指向一个调用门描述符时,该跳转就是利用调用门的跳转。这时如果选择子后跟着32位的地址 偏移,也不会被cpu使用,因为调用门描述符已经记录了目标代码的偏移。使用调门进行的跳转比普通跳转多一个步骤,即在访问调用门描述符时要将描述符当作 一个数据段来检查访问权限,要求指示调用门的选择子的
RPL≤门描述符DPL,同时当前代码段CPL≤门描述符DPL,就如同访问数据段一样,要求访问数据段的程序的CPL≤待访问的数据段的DPL,同时选择子的RPL≤待访问的数据段或堆栈段的DPL。只有满足了以上条件,CPU才会进一步从调用门描述符中读取目标代码段的选择子和地址偏移,进行下一步的操作。

      从调用门中读取到目标代码的段选择子和地址偏移后,我们当前掌握的信息又回到了先前,和普通跳转站在了同一条起跑线上(普通跳转一开始就得到了目标代码的段选择子和地址偏移),有所不同的是,此时,CPU会将读到的目标代码段选择子中的RPL清0,即忽略了调用门中代码段选择子的RPL的作用。完成这一步后,CPU开始对当前程序的CPL,目标代码段选择子的RPL(事实上它被清0后总能满足要求)以及由目标代码选择子指示的目标代码段描述符中的DPL进行特权级检查,并根据情况进行跳转。

【上篇】
【下篇】

抱歉!评论已关闭.