Linux从头学12:读完这篇【特权级】文章,你就比别人更“精通”操作系统!
扫描二维码
随时随地手机看文章
作 者:道哥,10 年的嵌入式开发老兵,专注于:C/C 、嵌入式、Linux。目录关注下方公众号,回复【书籍】,获取 Linux、嵌入式领域经典书籍;回复【PDF】,获取所有原创文章( PDF 格式)。
-
CPL:当前特权级
-
DPL:描述符特权级
-
RPL:请求者特权级
-
特权级检查规则
-
代码段的检查规则
-
数据段的检查规则
-
栈段的检查规则
-
理解了这3个特权级的保护规则,就理解了操作系统保护系统的终极密码!
- CPL: Current Privilege Level 当前特权级;
- DPL: Descriptor Privilege Level 描述符特权级;
- RPL: Requestor Privilege Level 请求特权级;
CPL:当前特权级
当前特权级,是指当前正在执行的代码的特权级别,它由当前正在执行的代码段寄存器cs中的bit[1 ~ 0]来决定:
当处理器进行一系列权限检查之后,允许进入这段代码中去执行,那么就设置cs = 0x0007。
- RPL: bit[1 ~ 0] = 11B,十进制就是 3,就表示这个选择子的请求特权级别是 3;
- TI: bit[2] = 1B,表示到 LDT 中查找段描述符;
- 索引号:bit[15 ~ 3] 的索引值为 0,表示到 LDT 中偏移量为 0 (0 = 0 * 4, 每个描述符占据 4 个字节) 的位置获取段描述符;
DPL:描述符特权级
DPL指的是一个段描述符中,用来指定这个描述符所代表的段,具有什么样的特权级别。
具体的比较规则,下文有描述。
RPL:请求者特权级
刚才的CPL内容中,已经描述了RPL是什么东西,它俩是密切相关的。
索引号:1;也就是说:当操作系统接受用户程序的请求之后,开始执行系统函数时,此时的CPL是操作系统的特权级别0。TI: 使用 LDT;
RPL: 3;
其实这里有一个隐患:
- 用户程序的数据段 DPL 一定是 3,这是由操作系统在加载程序之初就决定好的;
- 根据下文的特权级检查规则,这样的访问是允许的;
索引号:2(假设通过其它途径,知道操作系统的某个数据段位于 GDT 的第 2 个表项);此时,如果操作系统很无脑的就原样接收了用户程序的调用请求,就会通过GDT找到属于操作系统的数据段进行破坏性操作。TI: 使用 GDT;
RPL: 0;
特权级检查规则
代码段的特权级检查
一般情况下,只允许两个特权级相同的代码段进行转移。
但是处理器也提供了一些特殊途径,让低特权级的代码可以转移到高特权级的代码中去执行:
- 从用户程序的一个代码段(CPL = 3),跳转到另一个 DPL = 3 的代码段;
- 从操作系统的一个代码段(CPL = 0),跳转到另一个 DPL = 0 的代码段;
这里主要描述第一种情况,也就是当目标代码段描述符的TYPE字段中C = 1,也就是所谓的依从代码,或者一致性代码。
- 如果在高特权级代码段描述中的 TYPE 字段中,C = 1,就允许低特权级的代码转移进来;
- 通过调用门,低特权级代码也可以转移到高特权级的代码段;
CPL >= DPL例如:操作系统中有2个代码段,它们的描述符中的C标志位不同:RPL >= DPL
CPL == DPL最后还有一点需要记住:高特权级的代码,永远都不能转移到低特权级的代码。就好比:市长永远都不会以村长的身份去办事。RPL == DPL
数据段的特权级检查
数据段的特权级检查规则比较简单:高特权级的程序,可以访问低特权级的数据,反之不可以。
CPL <= DPLRPL <= DPL
栈段的特权级检查
栈段的特权级检查规则,也比较简单,x86处理器要求当前特权级 CPL 必须与目标栈段的 DPL 相同。
CPL == DPL为了满足这个要求,当从用户程序(CPL = 3)转移到操作系统(DPL = 0)时,如果是通过依存(一致性)代码段转移进去,当前特权级是不变的,此时使用的栈仍然是用户程序的栈空间。RPL == DPL
------ End ------
这篇文章主要从特权级的角度,来理解操作系统对系统的保护。