找回密码
 立即注册→加入我们

QQ登录

只需一步,快速开始

搜索
热搜: 下载 VB C 实现 编写
查看: 1624|回复: 1

【处理器】AMD64体系的逃跑机制和保留SSS机制以及人品机制

[复制链接]

65

主题

115

回帖

1万

积分

用户组: 超级版主

OS与VM研究学者

UID
1043
精华
35
威望
789 点
宅币
8294 个
贡献
1094 次
宅之契约
0 份
在线时间
2067 小时
注册时间
2015-8-15
发表于 2021-8-1 20:01:32 | 显示全部楼层 |阅读模式

欢迎访问技术宅的结界,请注册或者登录吧。

您需要 登录 才可以下载或查看,没有账号?立即注册→加入我们

×
本帖最后由 tangptr@126.com 于 2021-8-2 13:48 编辑

前言

去年我在论坛上发过AMD64体系的系统调用机制,而今年的二月,AMD发布了有关增强系统调用的白皮书
这篇白皮书英文名为AMD Supervisor Entry Extensions,即超威半导体设计的进入内核模式的扩展。
注意,该机制截止本文发表仅在白皮书阶段,打了草稿而已,还未发布过支持这种机制的CPU。

早期不足

早期的AMD64的系统调用体系是基于syscallsysret指令的,这两条指令不会自动地将CPU的所有状态切换到内核模式需要使用的状态,比如rsp寄存器,gs段等等。
此外,syscallsysret指令虽然可以通过SFMASK这个MSR实现原子性地屏蔽外部中断,但无法屏蔽不可屏蔽中断(NMI)。
AMD64体系下也存在异常重入的情况。举个例子,安全异常#SX(Security Exception)之内再次触发#SX可以导致异常的循环,而不是陷入双重故障,即#DF异常。(#SX异常是一种AMD系处理器才有的异常,目前的AMD系处理器的#SX异常只有一种触发的情况:当VM_CR这个MSR的R_INIT位(即Redirect INIT)置位后,处理器的INIT信号不再是初始化处理器状态,而是会被转换为#SX异常进入中断处理函数。)

增强系统调用

这个增强系统调用(Enhanced syscall/sysret)被简写为ESC,即Enhanced System Call。由于ESC常用于键盘上Escape键的缩写,故称之为逃跑机制。
ESC在AMD64体系中的EFERMSR中新增了ESCE位,表明是否启用ESC机制。
ESC还增加了STSTAR这个MSR。该MSR是syscall指令进入内核时指定的rsp寄存器的值,不再需要内核自行切换rsp了。AMD没有在白皮书里明说是不是启用了ESC机制才会用到这个STSTAR。从逻辑上说,如果不启用ESC就会使用STSTAR的话,会造成栈切换逻辑的混乱,系统调用入口会假设rsp指向用户模式栈,不了解ESC的OS内核不会设置STSTAR的值,从而在syscall指令后导致rsp的值不可预测。那么很明显,STSTAR应该是仅在启用了ESC机制后才会使用。
当ESC启用的时候,syscall指令会额外执行以下行为:

  1. 自动将gs的段基址与KernelGsBaseMSR的值相互切换,相当于自动执行了swapgs指令。
  2. STSTAR的值加载到rsp寄存器里。刚才提过了。
  3. 如果处理器启用了内核模式的影栈(即S_CETMSR中的第零位被置位),则将PL0_SSPMSR的值加载到ssp影栈寄存器。但不会自动地将其Busy位置位。这一条结合RSSS机制使用效果最佳。
  4. 执行syscall指令会在新的栈上填充syscall指令执行时的下一条指令的rip寄存器,以及当时的csss段选择子和rsp寄存器的值。
  5. syscall指令位于中断阴影之中时(Interrupt Shadow)时,挂起的调试异常会被弃置。所谓的中断阴影,指的是特定条件导致中断被暂时屏蔽,直到执行了下一条指令才会解除屏蔽的现象。这包括了我之前提到过的CVE-2018-8897漏洞中的mov ss,xx或者pop ss指令造成的中断屏蔽。那很明显,ESC机制的这一条就是冲着CVE-2018-8897漏洞去的。

当ESC启用的时候,sysret指令会执行以下额外的行为:

  1. 根据syscall额外行为的第四条,从内核栈上还原用户模式rsprip寄存器的值。
  2. 根据syscall额外行为的第一条,自动切换gs的段基址。
    注意,处理器不会在sysret指令中根据内核栈上的内容切换csss的段选择子,而是老样子根据STAR寄存器来切换csss的段选择子。

内核模式保留影栈

内核模式保留影栈(Reserved Supervisor Shadow Stacks,简写为RSSS)是一种增强切换影栈的机制。
RSSS机制在S_CETMSR中新增了一个RSSSE位用于启用RSSS机制。
在RSSS机制下,用wrmsr指令对PL0_SSP,PL1_SSP,PL2_SSP这三个MSR写入时会自动地将之前的影栈令牌的Busy位复位,将新的影栈令牌的Busy位置位。
也就是说,在RSSS机制下wrmsr写入这三个寄存器的行为暗含了一套clrssbsysetssbsy指令的操作。
如果复位旧影栈的Busy位时出错了,会抛出相关异常。比方说访问不合法的页会抛出#PF异常。但如果Busy位本来就是复位的,则不会抛出异常。
如果置位新影栈的Busy位时出错了,会抛出#CP异常,压入栈的异常码会表明是setssbsy错误。同时会将该MSR清零。
如果写入这三个MSR的值是零,则处理器只有写入的行为,不再有clrssbsysetssbsy的操作。
当启用了内核影栈时,权限跃迁会自动加载相应的MSR的值到ssp寄存器中,但不再会自动地将Busy位置位。

重入保护

重入保护(Re-Entrancy Protection)被简写为RP。由于RP常用于人品(拼音Ren Pin或Reputation Point声望值)的缩写,故称之为人品机制。
RP机制在EFERMSR中新增了一个RPE位标识是否启用RP机制。

异常行为

RP机制新增了一个EXCP_IN_PROG(即Exception In Progress)这个MSR,用于标记哪个异常正在进行。
由于现行AMD64体系的用于异常的中断向量仅限于0-31这32个入口,故可以猜测这个EXCP_IN_PROGMSR的高32位是保留的。
RP机制在IDT的段性质中指定第7位为RP位。如图所示:
idtrp.PNG
当该异常发生时,如果启用了RP机制且对应的中断入口的RP位置位时,那么EXCP_IN_PROGMSR的对应位就会被置位并进入异常。如果这个对应位已经被置位了,则会转换为#DF异常(双重故障)。如果此时产生的异常本来就是一个#DF异常,则转换为三重故障(Triple-Fault),处理器直接进入关机状态。
注意只有异常的IDT入口的RP位是有意义的。换言之向量值为32-255的中断是没有重入保护的。

异常帧

RP机制下的压入栈的异常帧的结构也有变化,如下图所示:
excp_frame.PNG
可以看到这里新增了两个字节,分别是Exception Information和Exception Vector。前者表示异常的一些信息,其位域在图中也标记出来了;而后者则表示异常的向量值。
值得注意的是,保存向量值并非毫无意义。其作用是为了让iret指令正确地对EXCP_IN_PROGMSR进行复位。

不可屏蔽中断

x86体系下的不可屏蔽中断(NMI)用的是IDT的2号中断。虽然NMI不是异常,但是在启用RP机制时,NMI也会把EXCP_IN_PROGMSR中的第二位置位。
值得注意的是,NMI自身具有屏蔽NMI的能力。换言之,处理器在处理NMI时会暂时屏蔽后来的NMI直到执行了iret指令后才会解除对NMI的屏蔽。这就造成了一个问题,如果NMI的过程中发生异常,而一般情况下异常也是通过iret指令实现返回的,那么NMI过程中的异常就会导致异常处理结束时就会导致处理器没有处理完NMI时就解除了对后来NMI的屏蔽。这就会造成OS处理NMI的逻辑错乱,而RP机制正好也弥补了这一缺陷。
当RP机制启用时,处理器在处理NMI时对于NMI的屏蔽不再是仅取决于是否执行了iret指令,而是依据EXCP_IN_PROGMSR的第二位。如果OS有特殊需要,可以提前将该位复位以解除NMI屏蔽。

机器检查异常

由于机器检查异常(Machine-Check Exception,简写为#MC)会将MCG_STATMSR中的MCIP位,在一定程度上#MC是不可重入的。#MC的重入会直接导致处理器进入关机状态,和三重故障(Triple-Fault)的效果相似。
如果将IDT中#MC的RP位置位,则重入的#MC会像其他异常一样被转换到#DF

其他特技

这一套扩展体系还包括了一些其他的非常有用的特技。

跨段加载栈特技

在AMD64体系中,iretretf指令会加载一个新的rsp的值。在原先的体系中,如果返回的ss段选择子是一个16位的段,则返回时只修改rsp的低16位。
这就导致系统软件有必要修改rsp的高位,否则会泄露OS的一些信息。
新处理器的体系确保整个64位的rsp的值都会被修改,而非依据ss段修改rsp
启用这个特技不需要特别设置。

调试异常屏蔽特技

当异常、软件中断、远调用、调用门发生于中断阴影中时,#DB异常会被自动弃置,而不再是屏蔽。如此一来,调试异常不再会导致权限跃迁的时候中断阴影导致调试异常处理函数识别错误的异常时权限。这是针对CVE-2018-8897漏洞加的特技。
启用该特技无需特别设置,但弃置的#DB异常不针对syscall指令。需要启用ESC机制才能针对syscall指令堵上CVE-2018-8897漏洞。

部分加载FS/GS

在支持ESC机制的处理器上,处理器新增了PARTIAL_FS_LOADPARTIAL_GS_LOAD两个MSR。系统软件可以对这两个MSR的低16位写入fsgs段选择子。
写入会使得处理器检查段选择子的合法性并加载fs/gs的段选择子、段性质和段限,但不会加载段基址。
可以把这两个新增的MSR理解为FSBASEGSBASE这两个MSR的对立面。

结语

个人认为AMD64出的白皮书里的规划还是相当不错的,尤其是在我去年详解过CVE-2018-8897漏洞的背景下,读到这份白皮书的我直呼AMD YES!
需要补充的是,除了“跨段加载栈特技”和“调试异常屏蔽特技”之外,其他的都是仅限于64位模式的。(没错,虽然AMD处理器的32位模式也支持syscall指令,ESC机制也是仅64位模式可用)

回复

使用道具 举报

0

主题

31

回帖

965

积分

用户组: 大·技术宅

UID
7423
精华
0
威望
12 点
宅币
900 个
贡献
10 次
宅之契约
0 份
在线时间
136 小时
注册时间
2021-9-8
发表于 2022-1-10 14:23:50 | 显示全部楼层
666, 楼主阅读白皮书很认真啊,我都看不下去
回复 赞! 靠!

使用道具 举报

QQ|Archiver|小黑屋|技术宅的结界 ( 滇ICP备16008837号 )|网站地图

GMT+8, 2024-4-20 04:09 , Processed in 0.038853 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表