5.4 特权级深入浅出
防止程序"越轨操作",于是给予其对应的权力。
5.4.1 特权级那点事
实际上就是检查访问者的特权级和受访者的特权级是否匹配。
特权级:0,1,2,3。数越小,权力越大。
- 0是内核级特权直接控制硬件。
- 1,2一般是虚拟机、驱动程序等系统服务。
- 3不用说了,就是用户程序。
5.4.2 TSS(任务状态段)简介
TSS (Task State Segment)任务状态段是处理器硬件原生系统级数据结构
- 最小(不加IO位图)104字节。
- 三个栈指针是为了不同特权级不同栈准备的。
两类特权级转移
- 低特权级转高:中断门,调用门等
- 要提前将高特权级的栈写入TSS中,在转高时会自动使用。
- 不需要写3特权级的栈,因为最低,没有更低的向它转移。
- 所以3级可以写入012,2可以写入01,1可以写入0的栈。
- 高特权级转低:调用返回指令
- 该操作是“回来”,因此由在“去*”的时候会将低特权的堆栈指针存放在转到的高级的栈指针位置,以便于再回来时继续使用低级栈。该过程称为向外层转移,但是高等级栈指针也会丢失,如果不人为进行更新的话。
TSS 由 TR(Task Register)寄存器加载。
5.4.3 CPL和DPL入门
指令是资源的请求者,指令“请求,访问”其他资源的能力等级即为请求特权级。
选择子中的RPL位代表代码请求资源能力的等级。代码段寄存器CS和指令指针寄存器EIP指向的指令就是当前处理器中正在运行的代码的等级。称为请求特权级或是当前特权级。
就是说处理器当前的特权级为CS.RPL也叫CPL(Current Privilege Level 当前特权级)。转移后的段的特权级称为DPL,也就是将要成为的CPL。
在段描述符中有个DPL,就是特权级。如果是当前的段,则该DPL就是当前的特权级。
DPL (Descriptor Privilege Level)描述符特权级
两个字节:可以代表 00b 01b 10b 11b特权级。
再次强调:访问者只能是代码段中的指令,因为数据段是不具备执行能力的。
当前的访问者只能说代码段DPL :.
- 受访者为数据段:只有 访问者DPL权限大于等于被访问者DPL权限才能继续访问。
- 受访问者为代码段:只有 访问者DPL权限==被访问DPL权限才能访问,即平级访问。
- 唯一的特殊情况:中断发生后,处理器从中断处理程序中返回到用户态。这是由高特权到低特权的。
不过该过程也仅仅是在目标段被访问的时候检查一下罢了。
既能执行高权限代码又不会获得高权限的方法。
利用一致性代码段。
段描述符中type中的C位来表示该段是否为已执行代码段。
1:一致性代码段。0:非一致性代码段。
非一致性只能平级转移。
一致性代码段又称依从代码段
- 转移后的DPL权限一定要大于转移前的CPL权限。
- 数值上:CPL(转移前) >= 一致性代码段DPL(转移后),比方3>=0。
- 转移后的特权级不会被DPL替换,而是保持原本的CPL,并未提升。
- 代码段可以有一直和非一致,但数据段只有非一致。
5.4.4 门,调用门与RPL序
门描述符和段描述符类似,都是8字节大小的数据结构。
除了任务门外,其他的对应的是一段函数。存放的是选择子和偏移量。
- 任务门可以放在GDT,LDT和IDT中。
- 调用门可以位于GDT,LDT中。
- 中断、陷阱门仅位于IDT中。
任务门、调用门都位于描述符表中,访问它们和普通的段描述符是一样的,必须通过选择子。
陷阱门和中断门只存在于IDT中,不能主动调用,只能通过中断信号触发。
任务门用任务TSS的描述符选择子来描述一个任务。
提供的四种门都可以实现从低特权级的代码段到高特权级的代码段。
- 调用门:call和jmp指令后接调用门选择子。
- 中断门:以int指令主动发中断。linux系统调用此中断门实现。
- 陷阱门:int3指令主动发中断。一般是编译器调试的时候。
- 任务门:任务以任务状态段TSS为单位,用来实现任务切换,也可以借助中断或指令发起。
访问者的特权级再低也不能比门描述符的DPL特权低。
三者关系:
- 门的特权级要低于等于当前特权级。
- 当前特权级要低于等于目标特权级。
**在调用门为了实现例程时,会通过压栈的方式传入参数。会造成一个问题:低特权的时候在低特权栈中传入参数,调用高特权后,那参数这么搬到高特权栈中?事实上,处理器在固件上已经实现了自动复制,会将用户进程压在3特权栈中的参数自动复制到0特权栈中。**调用门的高32位中,前5位就是参数个数。最多31个参数。
5.4.5 调用门的过程保护
三特权通过call使用调用门到特权级0
- 在call调用门之前在3特权级栈中压入参数。
- 根据门描述符中选择子对应的目标代码段DPL,这里假设为0。处理器自动在TSS中找到合适的栈段选择子SS和栈指针ESP,它们作为转移后的新栈。记为 SS_new ESP_new。
- 检查新栈段选择子对应的DPL和type,如果未达标则处理器引发异常。
- 如果转移后的DPL比CPL更高。为了特权级转换,需要切换到新栈。转移前也要将SS_old和ESP_old存入新栈中。这样才能在恢复时返回。而在未加载SS_new和ESP_new时,处理器会先找个地方临时保存两个old。之后将两个new加载到栈段寄存器和栈指针寄存器中。
- 启动新栈后将ss_old和esp_old压入新栈中,因为是新栈32位,旧的16位高位由0填充。
- 根据调用门描述符中的参数个数决定复制几个参数。
- 使用调用门调用后,将旧的cs,eip加载到栈中。
- 加载调用门中的代码段选择子到cs,将偏移量加载到eip。
如果是平级转移,则当作直接远转移,跨过中间几步,直接做第7部。
retf指令从调用门返回的过程
- 检查cs选择子的rpl位。
- 栈中弹出eip_old到eip,弹出cs_old到cs中。
- 跳开参数,让esp_new指向esp_old.
- 将esp_old加载到esp寄存器和ss_old加载到ss寄存器。
如果ds没有人为修改,还是高权限的话会被填充0,指向0哑描述符,引发处理器异常。
5.4.6 RPL的前世今生
RPL(Request Privilege Level)请求特权级:真正资源请求者的CPL。
在请求某特权等级资源时,检查的不只有CPL还有RPL。
RPL和CPL的特权必须同时大于等于受访者的特权DPL。
恍然大悟特权级
5.4.7 IO特权级
IO位图只有在数值上CPL>IOPL,当前特权级比IOPL低时才有效,若当前特权级高于IOPL时,任何端口都可以直接访问。
I/O位图位于TSS中,可以存在,可以不存在。