我正在阅读这篇关于类似于Spectre的理论CPU漏洞的文章,它指出:
"攻击者需要训练分支预测器,使其 可靠地错误预测了分支。
我大致了解什么是分支预测以及它是如何工作的,但是"训练"分支预测器意味着什么?这是否意味着偏置一个分支,使其计算成本比另一个分支高得多,或者是否意味着(在循环中(在继续下一个错误预测的分支之前,不断让 CPU 正确预测特定分支?
例如,
// Train branch predictor
for (int i = 0; i < 512; i++)
{
if (true){
// Do some instructions
} else {
// Do some other instruction
}
}
// The branch predictor is now "trained"/biased to predict the first branch?
// Proceed to attack
分支预测变量是否使用权重来偏向预测,还是基于以前的预测/错误预测以一种或另一种方式偏置?
这意味着创建一个分支来别名你正在攻击的分支(通过将其放在一个特定的地址,也许是与另一个进程中相同的虚拟地址,或者 4k 或其他 2 次偏移量可能有效(,并运行它多次以偏向预测因子。
这样,当你用幽灵攻击的分支实际运行时,它会按照你想要的方式被预测。 (或者对于间接分支,将跳转到您想要的虚拟地址(。
现代 TAGE 分支预测因子索引基于分支历史(导致该分支的动态指令流中的其他分支(,因此正确的训练可能很复杂......
但在最简单的层面上,是的,具有超过 1 位状态的分支预测器记住的不仅仅是最后一个分支方向。维基百科有一篇关于分支预测的许多不同实现的大文章,从简单的 2 级饱和计数器开始。
训练他们包括让你控制的分支重复走同样的方式。
具体来说,你会把这样的东西放在一个循环中(在一个已知的地址(,然后重复运行它。
xor eax,eax ; eax=0 and thus set ZF
jnz .target ; always not-taken
然后目标分支将失败并运行您想要的 Spectre"小工具",即使它通常被占用。
分支预测器通过记住最近的分支目标来工作。 最简单的预测形式只是记住上次击中哪个分支;存在更复杂的预测变量,并且很常见。
"训练"只是填充了这段记忆。 对于简单(1 值(预测变量,这意味着采用您想要支持的分支一次。 对于复杂预测变量,这意味着多次执行首选分支,直到处理器可靠地预测所需的结果。