CPU的保护机制不仅仅表现在对于表限和段限的检查,还要进行各种各样的Type Cheking。类型检查的种类繁多,检查的时机以及涉及到的结构和寄存器也很多,这篇文章中仅仅介绍以前学习过的结构和寄存器的检查,像LDT,TSS这样的结构和寄存器的检查会在后面继续学习。
CPU在不同的时机进行类型检查,这些时机主要有:
- 将段选择子加载到段寄存器中
- 指令通过段寄存器访问段
- 运行一个带有段选择子的操作数的指令
- 在某些内部操作的时候
这些检查主要针对两个区域:
- S(descriptor type) flag
- Type field
S flag表示段是系统段还是代码/数据段,Type根据S的不同有不同的含义。
加载段
当将一个段选择子加载到段寄存器的时候,CPU只允许某种类型的段寄存器包含特定类型段描述符类型,Intel官方文档中给出了几种情况,我们按照Intel给出的情况写出了一些例子代码:
- %cs寄存器仅能够加载代码段的选择子
这个例子很好构造,只要给%cs加载其他段的选择子就会产生#GP:
# load data segment selector into code segment register.
# trigger #GP exception
movw $data_selector, %ax
movw %ax, %cs
- 只读的代码段和系统段不能够加载到数据段寄存器(%ds, %es, %fs和%gs)
为了构造这个例子,我们需要在GDT中添加一个系统段描述符:
system_descriptor:
.quad 0x00cf82000000ffff
系统段描述符的S==0,在保护模式代码中将系统段选择子加载到%ds,就会产生#GP:
# load system segment selector into data segment register.
# trigger #GP exception
movw $system_selector, %ax
movw %ax, %ds
- 只有可写数据段才能加载到堆栈段寄存器
data_descriptor:
.quad 0x00cf90000000ffff
然后在保护模式代码中将它加载给%ss,这样就会产生#GP:
# load read-only data segment selector into stack segment register.
# trigger #GP exception
movw $data_selector, %ax
movw %ax, %ss
上述三个例子运行结果是相同的:
访问段
当指令通过段寄存器访问段的时候,CPU规定指令只可以使用预定义的方式访问某些段,Intel官方文档中也给出了一些例子:
- 不可以向可执行段中写数据
这个例子很好构造,代码段是可执行段,我们只要向代码段中写数据就可以触发#GP异常:
# write into executable segment.
# trigger #GP exception
xorl %eax, %eax
movl %ebx, %cs:(%eax)
- 不可以向只读数据段中写数据
data_descriptor:
.quad 0x00cf90000000ffff
然后再向数据段中写入数据就可以触发#GP异常:
# write into read-only data segment.
# trigger #GP exception
xorl %eax, %eax
movl %ebx, %ds:(%eax)
- 当可读标志没有设置的时候不可以读取可执行段
code_descriptor:
.quad 0x00cf98000000ffff
然后从代码段中读取数据就会触发#GP异常:
# read into executable-only segment.
# trigger #GP exception
xorl %eax, %eax
movl %cs:(%eax), %ebx
这三个例子的运行结果也是一样的:
运行带有段选择子的指令
- lcall或者ljmp指令只能够访问代码段,调用门,任务门或者TSS
这个#GP很好触发,我们可以让ljmp跳转到数据段:
# a far jmp instruction access data segment.
# trigger #GP exception
ljmp $data_selector, $0x00
这个例子的运行结果:
其他
Intel文档中给出了很多检查类型的时机以及例子,不过很多都涉及到了我们没有学习到的数据结构和寄存器,这里就不再举例了。
参考
《Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3 (3A, 3B & 3C): System Programming Guide》
《自己动手写操作系统》
《x86/x64体系探索与编程》