2021年是否可移除MASM Spectre V2防护宏依赖微码及编译器修复?
背景信息
几年前,我为自家MASM代码库编写更新了如下宏,用于防御Spectre V2(CVE-2017-5715 分支目标注入):
NOSPEC_JMP MACRO target:REQ PUSH target JMP x86_indirect_thunk ENDM NOSPEC_CALL MACRO target:REQ LOCAL nospec_call_start LOCAL nospec_call_end JMP nospec_call_end ALIGN 16 nospec_call_start: PUSH target JMP x86_indirect_thunk ALIGN 16 nospec_call_end: CALL nospec_call_start ENDM .CODE ;; 这是用于阻止CPU对间接调用进行推测执行的特殊指令序列。 ALIGN 16 x86_indirect_thunk: CALL retpoline_call_target ;; capture_speculation分支目标仅可能被推测执行,对齐无收益。 capture_speculation: PAUSE JMP capture_speculation ALIGN 16 retpoline_call_target: IFDEF WIN64 LEA RSP,[RSP+8] ELSE LEA ESP,[ESP+4] ENDIF RET
使用示例如下,为开启推测执行防护(MST_QSPECTRE=1)的汇编代码:
main PROC NEAR C PUSH ESI PUSH EDI PUSH EBX PUSH EBP MOV EAX,OFFSET MyFun ;; 生成无推测执行风险的间接指针调用代码。 IFDEF MST_QSPECTRE NOSPEC_CALL EAX ELSE CALL EAX ENDIF POP EBP POP EBX POP EDI POP ESI RET main ENDP
反汇编结果可显示推测执行防护指令的插入情况:
当前已知C语言场景下,微软MSVC已提供/Qspectre编译选项、GCC也可通过-mfunction-return等选项实现Spectre v2缓解,同时CPU厂商已推送相关微码更新。
问题答复
2021年你不能安全移除上述自定义MASM防护宏,仅靠CPU微码更新无法完全解决Spectre相关安全隐患,核心原因如下:
- 微码更新本身不具备全场景覆盖能力:首先多数CPU的Spectre V2硬件级缓解(如IBRS、IBPB等)需要软件主动触发调用才会生效,不是更新微码后就自动运行;其次大量老旧型号CPU(包括停产的消费级CPU、工业控制场景专用CPU)厂商不会提供对应的Spectre缓解微码更新,运行在这类设备上的代码如果移除宏防护,会直接暴露在攻击风险下;另外部分微码级缓解的性能开销远高于你实现的retpoline软件防护,硬切微码方案反而会带来不必要的性能损失。
- 编译器防护无法覆盖汇编代码:MSVC的
/Qspectre、GCC的相关缓解选项只会处理C/C++编译器生成的代码,你手动编写的MASM汇编代码不在编译器的自动处理范围内,移除宏之后,汇编里的间接调用、间接跳转完全没有防护,直接裸奔。 - 多层防护的必要性:即便微码+编译器防护已经覆盖了大部分攻击面,自定义的宏防护作为针对汇编代码分支的精准兜底防御,可以进一步降低整体攻击面,符合纵深防御的安全原则。
如果想要降低自定义宏的维护成本,可以做适配优化:增加运行时CPU特性检测逻辑,当检测到运行环境的CPU支持完善的硬件级Spectre缓解时走原生调用分支,不满足条件的场景依然走宏实现的retpoline防护,不要直接全量移除宏。
内容的提问来源于stack exchange,提问作者vengy
相关产品推荐
相关产品推荐

