文章系列:
重新认识Intel权限检查(一)
重新认识Intel权限检查(二)
原理
权限检查作为保护模式的一种表现在386被引入,本章介绍不使用调用门时的权限检查,不涉及特权级变化。
- 检查原则
一句话概括,代码段分一致和非一致,一致代码段允许同级和低级代码跳转访问,非一致代码段只允许同级访问;数据段总是非一致的,不允许低级代码访问,只允许同级代码访问。一致性代码被访问时RPL不参与权限检查。
高级代码访问低级代码和数据涉及特权级变化,这里不做讨论。
一致代码:Conforming Code
非一致代码:None-Conforming Code - 相关结构和寄存器
-
RPL(Request Privilege Level),CPU请求权限,保存在段选择子中。
-
CPL(Current Privilege Level),CPU当前权限,保存在CS中。
-
DPL(Descriptor Privilege Level),段描述符权限,保存在描述符属性域中。
-
- 代码访问检查流程
- CPU执行转移指令,获取段选择子
- GDT/LDT中查找描述符(TI=0,GDT;TI=1,LDT)
- 如果段类型为一致代码段,CPL权限小于等于DPL就符合权限,可以跳转。RPL值不考虑。
- 如果段类型为非一致代码段,CPL权限等于DPL同时RPL不能低于DPL,可以跳转。RPL需要考虑。
- 如果段类型为数据段
实验
- 准备阶段
系统上电到保护模式后默认是ring0,处于最高特权级,想要验证时需要retf返回到低特权级,这里选择ring2。贴出跳转到ring2的关键代码。进入保护模式代码参见重新认识intel段机制寻址方式
主要流程- 准备ring2堆栈段和代码段
- 计算ring2堆栈段基址和代码段基址,填入描述符表
- 计算ring2堆栈段选择子和代码段选择子
- 堆栈选择子压栈,堆栈Top压栈,代码段选择子压栈,retf
1)准备ring2堆栈段
; ring2 堆栈段
[SECTION .s2]
ALIGN 32
[BITS 32]
LABEL_STACK2:
times 32 db 0
TopOfStack2 equ $ - LABEL_STACK2 - 1
; end of .s2
2)准备ring2代码段,复用ring0的代码,复用手段:准备两条描述符权限分别是ring2和ring0,描述符中基址指向同一段代码。
[SECTION .s32]; 32 位代码段. 由实模式跳入.
[BITS 32]
LABEL_SEG_CODE32:
str ax
cmp ax, SelectorTSS ; 检查TR是否被加载,如果加载不再重复
je .1
mov ax, SelectorTSS ; 加载TR
ltr ax
.1:
mov ax, cs
and ax, 10b
cmp ax, 10b ; 判断CPL
je .2 ; 如果CPL!=2,retf到ring2,否则跳转到.2执行测试代码
push SelectorStack2 ;ring2堆栈段选择子压栈
push TopOfStack2 ;栈顶指针压栈
push SelectorCode32R2 ;ring2代码段选择子压栈
push 0
retf
3)计算段基址,填入描述符表
[SECTION .gdt]
; GDT
; 段基址, 段界限 , 属性
LABEL_GDT: Descriptor 0, 0, 0 ; 空描述符
LABEL_DESC_CODE32: Descriptor 0, SegCode32Len - 1, DA_C + DA_32; 非一致代码段
LABEL_DESC_CODE32R2: Descriptor 0, SegCode32Len - 1, DA_C + DA_32 + DA_DPL2; 非一致代码段
; gdt初始化 32 位代码段描述符
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32 ; 指向LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32 + 4], al
mov byte [LABEL_DESC_CODE32 + 7], ah
; gdt初始化 32 位代码段描述符 ring2
xor eax, eax
mov ax, cs
shl eax, 4
add eax, LABEL_SEG_CODE32 ; LABEL_SEG_CODE32
mov word [LABEL_DESC_CODE32R2 + 2], ax
shr eax, 16
mov byte [LABEL_DESC_CODE32R2 + 4], al
mov byte [LABEL_DESC_CODE32R2 + 7], ah
- 测试阶段
- 目的段是一致码段,RPL=3,CPL=2,DPL=2,Confoming
RPL不参与权限检查,无论RPL是0,1,2,3都无所谓
关键代码
- 目的段是一致码段,RPL=3,CPL=2,DPL=2,Confoming
LABEL_DESC_CODE32R2: Descriptor 0, SegCode32Len - 1, DA_CCO + DA_32 + DA_DPL2; 一致代码段
SelectorCode32R3 equ (LABEL_DESC_CODE32R2- LABEL_GDT) + SA_RPL3
.2: ; 测试代码,CPL=2
mov ax, SelectorVideo
mov gs, ax ; 视频段选择子(目的)
mov edi, (80 * 11 + 79) * 2 ; 屏幕第 11 行, 第 79 列。
mov ah, 0Ch ; 0000: 黑底 1100: 红字
mov al, 'P'
mov [gs:edi], ax
call SelectorCode32R3:0 ; RPL = 3, CPL = 2, DPL = 2 Confoming
SegCode32Len equ $ - LABEL_SEG_CODE32
确认:callf 0x0013:00000000
低4bit 0x3,RPL=3,cs:0x0012
CS低4bit 0x2,CPL=2,CS指向的描述符高双字dh=0x0040dd00
取其中DPL所在byte为0xd=1101b,DPL=2。同时DPL为一致码段。
- 目的段是非一致码段,RPL=1,CPL=2,DPL=2,Non-Confoming,检查通过
CPL必须等于DPL的同时,RPL要参与检查,必须权限大于等于DPL,小于DPL则不通过。
- 目的段是非一致码段,RPL=3,CPL=2,DPL=2,Non-Confoming,检查不通过
CPL必须等于DPL的同时,RPL要参与检查,必须权限大于等于DPL,小于DPL则不通过。