这次Google Project Zero引爆的深水炸弹,也意外的让“预测执行 (Speculative Execution)”、“非循序执行 (Out-Of-Order Execution)”和“分支预测 (Branch Prediction)”这些历史悠久的计算机结构专有名词,再度成为网络论坛的热门关键字。
为了方便各位科科瞬间理解上面三个名词的关系,请记得以下恒等式,不必谢我。
“预测执行 = 分支预测 + 非循序执行”,根据分支预测的结果,先斩后奏赌博性的执行指令,再借由非循序执行引擎维持指令执行顺序的一致性,与回复当预测错误时的处理器状态,各位只要知道这些就够了。
如果一时之间还搞不懂为何要这样作,请重新想清楚“电脑 (Computer)”和“计算器 (Calculator)”最大的不同之处:电脑最重要特征在于“条件判断”的能力,根据不同的条件,执行不同的指令流。
如果你不想看到整条指令管线,因为等待确认条件判断的结果而停摆,就需要设计一个纪录分支历史的小型快取内存,根据其内容“以古鉴今”去预测分支是否发生,或著发生后会跳到哪个内存位址,再继续撷取并预测性的执行指令。
分支预测当然也有可能发生错误,像循环 (Loop) 就是一例,反复发生 (Taken) 后,起码最后一次就不会发生 (Not Taken),这也暗示了我们可以借由“训练”分支预测,使其错误地预测执行不应被执行的程式码。
既然系统权限已经受到重重保护,为何还会被“僭越”?
我们前面有看到处理器会有不同的程式执行权限与内存保护机制,但为何还会发生“下犯上”使用者模式可以读取到系统核心资讯的惨剧,原因很简单,因为预测执行“冲过头”了,将不应该被应用程序存取到的内存位置,跳过权限检查,被预先载入快取内存,即使此预测执行作废,该内存位址区段仍在快取内,此时此刻有心人就有上下其手的机会,例如可“旁敲侧击”观察内存存取的反应时间 (被快取到当然会更短),判断这段内存位址是否属于系统核心。
事实上,近代高效能处理器的预测与非循序执行,并非仅限于指令,连内存存取这档事都可雨露均霑,不按牌理出牌,在x86世界源自于Intel Core微架构“Merom”的“内存资料相依性预测功能 (Memory Disambiguation)”即为最好的范例,根据预测,承受后面的内存载入指令、可能需要前面载入执行结果的相依性风险,不等待前面回存 (Store) 指令完成工作,大胆的提前载入 (Load) 内存位址,以确保指令管线不停顿的顺畅运转。
一图胜千言,直接引用Intel当年介绍Merom的简报。原本Load4要等待Store3完成。
▲有了内存资料相依性预测功能,不等Store3,Load4就赌下去了。当然,如果赌错了,后头要收拾残局的成本就非常的高,大约40个时脉周期就飞了,但看在赌对了就赚翻了的份上,硬著头皮还要给他赌下去。
▲有没有突然感觉到,这些处理器设计者好像都蛮“赌性坚强”?
很不幸的,Intel刚刚好就是这群赌徒中,特别敢冒险的那位 (Intel其实在微架构设计上一直蛮激进的),有时候还真心觉得夜路走多了真的会碰到鬼,的确不是骗人的,Google Project Zero就活见“鬼”了。
成本高昂的分页表隔离
前一篇有提到透过分页表管理虚拟内存的配置,需要权限保护的操作系统核心,与一般使用者的应用程序,实际上是会有可能混在一起的。以32位元Linux为例,理论上应用程序可以看到4GB的虚拟位址,但其实最上面1GB的属于系统核心;32位元Windows也有类似的限制,1GB或2GB切给操作系统核心与驱动程式,所以应用程序只能使用到3GB或2GB。
简而言之,应用程序的确有机会利用某些漏洞,存取本应不该被允许的系统核心资讯。
那你也许会问:既然如此,为何我们不坚壁清野,维护两份独立的分页表,一份系统核心,一份使用者,不就功德圆满了?
但每次系统呼叫,都需要反复切换分页表并搬移大量的资料,尤其用来加速虚拟位址转换实体位址的TLB (Translation Lookaside Buffer) 会一直“上冲下洗 (Flush)”,等于每次系统呼叫都要重建快取资料,想闪也闪不开,导致严重的效能损失,这也是为何主流操作系统都将敏感的系统核心资讯,安置在虚拟位址的高位,并透过将程式码与资料“随机性”的散布其内,以避免当某个漏洞被发现时,被用来“一招半式打天下”,难以采用通用手段危害操作系统的强固性。
但很不幸的,Google Project Zero的研究成果,终究还是将操作系统厂商逼回成本高昂的“隔离”手段,最起码眼前的短期方案仅限于此,能否有更低成本的手段,还在未定之天。往好处想,无须系统呼叫的纯运算工作,效能应该不会受到什么影响,也许吧。
对x86处理器来说,问题就更大条了,两份独立的分页表,意味着避开昔日16位元时代遗产“节区 (Segment) 内存定址”的“平面 (Flat) 内存模式”就此破功,对于那些早已“放生”老旧内存定址模式效能的新型x86处理器微架构来说,实在是不堪回首的严酷考验,这就像一道旋转们,你越积极的抛弃遗产让微架构针对未来最佳化,你背后被老旧包袱狠狠集中的后座力也越大,所谓“牙膏挤了原来还能吸回去”,大概就是这么一回事。






























