保护模式中的特权级

简介: 保护模式中的特权级

引言

  • 在上一章节中提过,调用门可以实现不同特权级的代码之间跳转执行
  • 不能直接跳转吗?我们先来做个小实验
  • 将 Task A 中代码段选择符中的特权级由 0 改 为 3 ,然后编译运行一下看看效果
; TASK_A_CODE32_SELECTOR equ (0x0000 << 3) + SA_RPL0 + SA_TIL
TASK_A_CODE32_SELECTOR equ (0x0000 << 3) + SA_RPL3 + SA_TIL
  • 实验结果:原本应该打印的字符串 “Task A”,并没有打印出来,程序崩溃了
  • 结论:不同特权级的代码之间并不能随意跳转
  • 想要搞清楚原因,就需要先对特权级进行一定的了解

特权级

  • 我们知道,保护模式下, CPU 提供各种各样的保护机制,比如段界限,指定范围;段属性,指定读写等权限等等。这些都比较好理解,在这里就不总结了
  • 保护模式下, CPU 还提供了有关特权级的保护机制
  • 处理器的段保护机制可以识别 4 个特权级(或特权层),0 级到 3 级。数值越大,特权越小

  • 处理器利用特权级来防止运行在较低特权级的程序或任务访问具有较高特权级的一个段
  • 我们熟知的 linux 系统只使用了特权级 0(内核)和特权级 3(应用)

与特权级相关的三个概念

  • 当前特权级 CPL(Current Privilege Level)
  • CPL 是当前正在执行程序或任务的特权级。它存放在 CS 和 SS 段寄存器的位 0 和位 1 中
  • 当程序把控制转移到另一个具有不同特权级的代码段中时,处理器就会改变 CPL
  • 处理器进入保护模式后,CPL = 0(最高特权级)
  • 描述符特权级 DPL(Descriptor Privilege Level)
  • DPL 是一个段或门的特权级。它存放在段或门描述符的 DPL 字段中
  • 在当前执行代码段试图访问一个段或门时,段或门的 DPL 会用来与 CPL 以及段或门选择符中的 RPL 作比较
  • 根据被访问的段或门的类型不同,DPL 也有不同的含义,这里先不深究,后面再做介绍
  • 请求特权级 RPL(Request Privilege Level)
  • RPL 是一种赋予段选择符的超越特权级,它存放在选择符的位 0 和位 1 中
  • 处理器会同时检查 RPL 和 CPL,以确定是否允许访问一个段

CPL、DPL 和 RPL 的关系

  • 当处理器从 A 代码段成功跳转到 B 代码段执行
  • 跳转前: CPL = DPL(A)
  • 跳转后: CPL = DPL(B)
  • 当处理器运行过程中需要访问数据段时
  • CPL <= DPL(Data)
  • 在请求某特权级为 DPL 级别的资源时,参与特权检查的不只是 CPL,还要加上 RPL. CPL 和 RPL 的特权必须同时大于等于受访者的特权 DPL,即:数值上 CPL <= DPL 并且 RPL <= DPL

再做小实验

  • 先对段描述符中 DPL 属性进行宏定义
; 段描述符中 DPL 属性定义(段描述符高 32 位的 bit13-bit14 )
DA_DPL0     equ    0x00  ; DPL = 0
DA_DPL1     equ    0x20  ; DPL = 1
DA_DPL2     equ    0x40  ; DPL = 2
DA_DPL3     equ    0x60  ; DPL = 3
  • 给全局描述符表中 32 位代码段增加属性 DPL = 3
; CODE32_DESC : Descriptor 0, CODE32_SEG_LEN - 1, DA_C + DA_32
CODE32_DESC : Descriptor 0, CODE32_SEG_LEN - 1, DA_C + DA_32 + DA_DPL3
  • 运行一下,不出意外,果然不能运行,CODE32_START 代码段并没有运行,这说明高特权级代码段不能够跳转到低特权级的代码段
  • 将本章节 RPL、DPL 有关的改动都恢复一下,恢复后代码(可以运行):loader.asm
  • 同样的实验我们也在数据段上做一次,改动如下:
; DATA_DESC : Descriptor 0, DATA_SEG_LEN - 1, DA_DR + DA_32
DATA_DESC : Descriptor 0, DATA_SEG_LEN - 1, DA_DR + DA_32 + DA_DPL3
  • 运行一下,居然未发生任何错误
  • 再改一下:
; DATA_SELECTOR equ (0x0003 << 3) + SA_RPL0 + SA_TIG
DATA_SELECTOR equ (0x0003 << 3) + SA_RPL3 + SA_TIG
  • 还是未发生任何错误
  • 再改一下:
; DATA_DESC : Descriptor 0, DATA_SEG_LEN - 1, DA_DR + DA_32
DATA_DESC : Descriptor 0, DATA_SEG_LEN - 1, DA_DR + DA_32 + DA_DPL2
; DATA_SELECTOR equ (0x0003 << 3) + SA_RPL0 + SA_TIG
DATA_SELECTOR equ (0x0003 << 3) + SA_RPL3 + SA_TIG
  • 这回出错了,这说明请求特权级 RPL 不能够请求比它更高级的特权级数据段,但是可以请求到比它低级的特权级的数据段。
  • 再对栈段做下实验
  • 程序再次恢复到 loader.asm
  • 改动如下:
; STACK32_DESC : Descriptor 0, TOP_OF_STACK32, DA_DRW + DA_32
STACK32_DESC : Descriptor 0, TOP_OF_STACK32, DA_DRW + DA_32 + DA_DPL3
; STACK32_SELECTOR equ (0x0004 << 3) + SA_RPL0 + SA_TIG
STACK32_SELECTOR equ (0x0004 << 3) + SA_RPL3 + SA_TIG
  • 凭感觉栈段应该跟数据段一样,结果程序崩了。这说明栈段的特权级检测规则跟数据段不一样,好吧,代码段、数据段、栈段各自有各自的检测规则
  • 是不是有点乱糟糟的,暂时先不要一下子理清楚所有的规则,以后再在各种场景下具体体会,目前先有个感性的认识就好


目录
相关文章
|
2月前
ARM64技术 —— MMU处于关闭状态时,内存访问是怎样的?
ARM64技术 —— MMU处于关闭状态时,内存访问是怎样的?
|
6月前
|
编译器 程序员
进入保护模式
进入保护模式
58 0
|
6月前
|
存储 程序员 数据安全/隐私保护
保护模式
保护模式
116 0
|
6月前
|
存储 NoSQL 安全
保护模式下的中断
保护模式下的中断
110 0
|
6月前
|
安全 Linux Windows
中断处理与特权级转移
中断处理与特权级转移
109 0
|
C语言 Windows
[笔记] Windows内核课程:保护模式《一》保护模式
[笔记] Windows内核课程:保护模式《一》保护模式
|
Windows
[笔记] Windows内核课程:保护模式《二》段寄存器介绍
[笔记] Windows内核课程:保护模式《二》段寄存器介绍
|
编解码 编译器
4.1保护模式
4.1保护模式
133 0
|
存储 监控 数据安全/隐私保护