特权级(Privilege Level),是描述符和段选择子中的一个字段,当使用描述符或者选择子时,该字段用来控制将要进行的操作。比如说:切换一个段的时候就会对该段的特权级进行判断。
Intel CPU有4 个特权级别,分别是0 到3,较大的数值意味着较低的特权级别,在Windows中只采用了0和3,也就是常说的0环和3环,其中操作系统的代码处于0环特权级,而应用程序的代码赋予3环的特权级。
特权级(privilege)检查:
前面我们知道保护模式一共有三种类型特权级,分别是:
特权类型 | 内容 |
---|---|
CPL(Current Privilege Level) | 当前特权级,表明当前代码的特权级,CPL的值存放在CS段选择子寄存器的Selector字段的RPL字段中,SS段选择子寄存器的RPL和CS.Selector.RPL始终是一样的所以SS.Selector.RPL也是CPL。 |
DPL (Descriptor Privilege Level) | DPL存放在描述符里的DPL字段中,表明访问这些段所需要的权限。 |
RPL(Requested Privilege Level) | 存放在段选择子中的特权级字段,表明请求获得该段描述符时所提供的特权级。 |
对于特权级的检查,一般是在修改段寄存器时出现的检查。
比如说这样一段程序:
jmp 0x0010:0x00000000
mov ax,0x0008 ;0000 0000 0000 1000
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
其中0x0010和0x0008是段选择子,这里的段选择子就是进行请求更换段描述符的段选择子,所以里面存放的就是RPL(Requested Privilege Level)。
这段代码肯定要运行对吧,那么运行肯定就有运行的环境,而保护模式的环境下肯定是有CS,SS段寄存器的,此时CS,SS的段寄存器中的段选择子中的特权级就是CPL(Current Privilege Level)。而此时我们请求的段选择子肯定会对应一个段描述符,而这个对应的段描述符里也有一个特权级就是这里的DPL段特权级。
基本特权级检查
1: 高特权级别的程序可以访问低特权级别的数据段,但低特权 级别的程序不能访问高特权级别的数据段。访问数据段之前,肯定要对 段寄存器DS、ES、FS 和GS 进行修改,比如:
mov fs,ax
在这个时候,要求当前特权级CPL 和请求特权级RPL 都必须高于, 或者和目标数据段描述符的DPL 相同。即,在数值上,
CPL<=目标数据段描述符的DPL
RPL<=目标数据段描述符的DPL
2: 对于依从的段,要求当前特权级CPL和请求特权级必须小于或等于目标段描述符的DPL(用的比较少)
CPL>=目标代码段描述符的DPL
RPL>=目标代码段描述符的DPL
3: 对于栈段,要求当前特权级CPL和请求特权级必须等于目标段描述符的DPL
CPL == DPL
RPL== DPL
提高权限:
由于特权级的检测导致用户层只能在自己的特权级下进行工作,但是如果用户层也想调用内核层的代码实现某个功能怎么办?
这个时候就有了门的用处了,前面我们提到段描述符时讲到过系统段里面有Gate(门),这么一个特殊存在,它就是专门来让我们实现通过3环来到0环的空间的关键。
通过采用调用门,中断门,陷阱门和任务门可以来提高权限来帮助我们从3环到达0环: