问题标签 [speculative-execution]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
1 回答
1558 浏览

x86 - 当 Skylake CPU 错误预测分支时,究竟会发生什么?

我试图详细了解当错误预测分支时 Skylake CPU 管道的各个阶段中的指令会发生什么,以及来自正确分支目标的指令可以多快开始执行。

因此,让我们将这里的两条代码路径标记为红色(预测的,但未实际采用的)和绿色(采用的,但未预测的)。所以问题是: 1. 在红色指令开始被丢弃之前分支必须经过管道多远(以及它们在管道的哪个阶段被丢弃)?2. 绿色指令多久可以开始执行(就分支到达的流水线阶段而言)?

我查看了 Agner Fogg 的文档和大量的讲义,但在这些要点上并不清楚。

0 投票
1 回答
122 浏览

assembly - 为什么这个 Specpoline 不能在 Kaby 湖上工作?

我正在尝试在我的Kabe 湖 7600U上创建一个specpoline(cfr. Henry Wong),我正在运行 CentOS 7。

GitHub 上提供了完整的测试存储库。

我的 specpoline 版本如下(cfr.spec.asm):

这个版本与Henry Wong 版本的不同之处在于流程被转移到建筑路径中的方式。虽然原始版本使用固定地址,但我将目标传递到堆栈中。
这样,anadd rsp, 8将删除原始返回地址并使用人造的。

在函数的第一部分,我使用一些旧的 FPU 指令创建了一个长延迟依赖链,然后是一个试图欺骗 CPU 返回堆栈预测器的独立链。


代码说明

使用 FLUSH+RELOAD 1将 specpoline 插入分析上下文中,相同的程序集文件还包含:

buffer

跨越 256 个不同缓存行的连续缓冲区,每个缓存行由GAP-1行分隔,总256*64*GAP字节数。

GAP 用于防止硬件预取。

随后是图形描述(每个索引紧随其后)。

F+R 缓冲区

timings

一个由 256 个 DWORD 组成的数组,每个条目包含访问 F+R 缓冲区中相应行所需的时间(以核心周期为单位)。

flush

触摸 F+R 缓冲区的每一页(带有存储,只是为了确保 COW 在我们这边)并驱逐指定行的小功能。

“个人资料”

标准配置文件函数lfence+rdtsc+lence很好地用于分析 F+R 缓冲区中每一行的负载并将结果存储在timings数组中。

leak

这是执行实际工作的函数,称为specpoline在推测路径中放置商店和profile在架构路径中放置函数。

一个小的 C 程序用于“引导”测试工具。

运行测试

代码使用预处理器有条件地在架构路径中有条件地放置存储(实际上是在规范本身中),如果ARCH_STORE已定义,则有条件地在推测路径中放置存储(如果SPEC_STORE已定义)。

两者都存储访问 F+R 缓冲区的第一行。

运行make run_spec并将与相应的符号进行汇编,编译测试并运行它make run_archspec.asm

该测试显示了 F+R 缓冲区每一行的时序。

存储在建筑路径中

存储在推测路径中

我在架构路径中放置了一个商店来测试计时功能,它似乎有效。

但是,我无法通过投机路径中的商店获得相同的结果。

为什么 CPU 没有推测性地执行存储?


1我承认我从未真正花时间区分所有缓存分析技术。我希望我用了正确的名字。FLUSH+RELOAD 我的意思是驱逐一组行的过程,推测性地执行一些代码,然后记录访问每条被驱逐行的时间。

0 投票
1 回答
783 浏览

assembly - 为什么要为其他逻辑处理器导致的 Memory Order Violation 刷新管道?

vTune 文档将Memory Order Machine Clear 性能事件描述为:

当来自另一个处理器的窥探请求与管道中数据操作的源匹配时,会发生内存排序 (MO) 机器清除。在这种情况下,管道在正在进行的加载和存储退出之前被清除。

但是我不明白为什么会这样。不同逻辑处理器上的加载和存储之间没有同步顺序。
处理器可以假装在所有当前进行中的数据操作都提交之后发生了窥探。

这里也描述了这个问题

每当 CPU 内核检测到“内存排序冲突”时,就会触发内存排序机器清除。基本上,这意味着一些当前未决的指令试图访问我们刚刚发现其他一些 CPU 内核同时写入的内存。由于这些指令仍被标记为待处理,而“此内存刚刚被写入”事件意味着其他内核成功完成了写入,待处理的指令——以及依赖于它们结果的所有内容——追溯起来是不正确的:当我们开始执行这些指令时说明,我们使用的内存内容版本现在已经过时了。所以我们需要把所有的工作都扔掉,然后再做一遍。那是机器清楚的。

但这对我来说毫无意义,CPU 不需要重新执行加载队列中的加载,因为非锁定加载/存储没有总顺序。

我可以看到一个问题是允许重新排序负载:

如果执行顺序是 1 3 2 那么像mov [foo], 13 和 2 之间的存储会导致

这确实会违反内存排序规则。

但是负载不能随负载重新排序,那么当来自另一个内核的窥探请求与任何运行中负载的源相匹配时,为什么英特尔的 CPU 会刷新管道?
这种行为防止了哪些错误情况?

0 投票
1 回答
503 浏览

security - MSBDS(辐射)背后的微架构细节是什么?

CVE-2018-12126 已被分配给 MSBDS(微架构 StoreBuffer 数据采样),这是英特尔处理器的漏洞,属于新创建的MDS(微架构数据采样)类。

我试图了解这些漏洞背后的微架构细节。我从 MSBDS 开始,也称为 Fallout (cfr Meltdown),它允许攻击者泄露存储缓冲区的内容。

出于某种原因,讨论微架构细节的网络安全论文往往不够精确。
幸运的是,MSBDS 论文引用了专利 US 2008/0082765 A1(从中拍摄图片)。

据我所知,在 MSBDS 的情况下,漏洞似乎在于内存消歧算法如何处理带有无效物理地址的负载。

这是据称用于检查存储缓冲区中的负载是否匹配的算法:

加载和存储的内存消歧算法

302检查加载所引用的页面的偏移量是否与存储缓冲区中任何先前存储所引用的页面的偏移量相匹配。
如果此检查失败,则负载与任何存储都不匹配,并且可以在304处执行(它已被分派) 。
如果302进行检查,则将加载的虚拟地址的上半部分与存储的虚拟地址进行检查1
如果找到匹配,则加载匹配并且在308转发它需要的数据或者如果转发是不可能的(例如,将存储缩小到更广泛的加载),加载本身被阻塞(直到匹配的存储提交)。
笔记相同的虚拟地址可以映射到两个不同的物理地址(在不同的时间但在存储转发窗口内)。不正确的转发不是通过这种算法来防止的,而是通过排空存储缓冲区(例如,使用mov cr3, X正在序列化的 a)2来防止。
如果加载的虚拟地址不匹配存储的任何虚拟地址,则在310检查物理地址。
这是处理不同虚拟地址映射到相同物理地址的情况所必需的。

[0026]段补充说:

在一个实施例中,如果在操作302存在命中并且加载或存储操作的物理地址无效,则在操作310的物理地址检查可以被认为是命中并且方法300可以在操作308继续。在一种情况下,如果加载指令的物理地址无效,则加载指令可能由于DTLB 118未命中而被阻塞。此外,如果存储操作的物理地址无效,则结果可以基于一个实施例中的finenet命中/未命中结果,或者可以在该存储操作上阻止加载操作直到存储操作的物理地址被解析在一个实施例中。

这意味着如果物理地址不可用,CPU 将只考虑地址的低 (12) 位3
考虑到 TLB 未命中的情况在下面几行中得到解决,这仅留下访问页面不存在的情况。

这确实是研究人员提出他们的攻击的方式:

我不确定还有什么会导致无效的物理地址(对特权页面的访问返回正确的物理地址)。

真的是对无效物理地址的处理触发了MSBDS漏洞吗?


1 SBA(存储缓冲区地址)组件包含存储的虚拟地址和物理地址,可能只是物理地址的一部分(其余部分位于专用数组中,可能命名为物理地址缓冲区)。
2我不清楚是否真的有可能通过将页表条目更改为指向其他地方然后发出invlpg.
3我对此的理由是,由于我们不处于可恢复的情况下,负载出现故障,跳过另一个检查以冒不正确转发的风险在性能方面是值得的,因为它会使负载提前退出(和故障)。

0 投票
0 回答
81 浏览

x86 - ZombieLoad 的微架构根本原因是什么?

我的解释是,在 TLB 未命中时,PMH 遍历页表并将填充加载到加载缓冲区中;如果它遇到需要设置的访问位或脏位,它会传达一个异常代码,该代码将标记加载退出(假设它还将加载需要帮助的虚拟地址放置在 MSROM 例程可访问的位置)。

当它退休时触发异常,导致管道被刷新,并且特定的 MSROM 特殊 uop 在分配阶段表现出来,这将重新执行整个步行(不知道为什么 PMH 不能自己执行填充写入,但是这个是关于会发生什么的普遍信念)。这看起来确实很奇怪,因为这意味着必须有一个 uop 指示存储到一个物理地址,如果 PMH 执行填充存储,就不必有这样的 uop。如果遇到无效或受保护的位,特殊的 MSROM uop 问题将不得不跳转到页面错误异常例程。如果不需要设置脏/访问位,则将由 PMH 传达页面错误异常代码。

该论文建议继续加载,L1d 缓存控制器只是返回——而不是一个虚拟值或 0 以及取消加载的异常代码——行填充缓冲区的内容可能仍包含由其他逻辑填充的内容核心(然后可用于暂时修改缓存以进行缓存定时攻击)。

这只是英特尔的一个愚蠢错误吗?前所未有的副作用?

0 投票
0 回答
79 浏览

arm - Arm Cortex-A8 程序流预测

我正在检查 ARM-Cortex A8 流预测能力,为了做到这一点,我实现了以下代码:

在上面的代码中,我将执行 8 次条件为真的 if 语句来训练 CPU 的分支预测器,在第 9 次我希望 cpu 可以推测性地访问 SecretDispatcher[9 * 512],但条件不正确。这只是简单的 Spectre-v1 PoC 攻击,我在 Intel X86 处理器上以相同的逻辑成功实施了这种攻击,我希望这项工作也可以在 Cortex-A8 中工作,因为 arm 澄清该处理器容易受到这种攻击。

有什么我想念的吗?我应该做些什么来启用 ARM-Cortex A8 上的程序流预测?

0 投票
1 回答
86 浏览

speculative-execution - 英特尔 CPU 上的推测执行是否可能导致 EXC_BAD_INSTRUCTION (SIGILL)

我有一个假设,即 Intel Nehalem(第 1 代)上的推测性执行会导致崩溃。有可能还是我完全错了?如果这是可能的,我能做些什么来防止这种情况发生?也许只对一个函数或整个翻译单元禁用推测执行?

对于有问题代码的 cpp 文件的编译,clang 与标志一起使用 -mavx2 -mxsave 所有其他没有这些标志编译的文件。此代码适用于任何可用的当代 Mac 书和 Windows 笔记本电脑/台式机。

Testers mac book 有 Intel(R) Core(TM) i5 CPU 760。这个 CPU 不支持 AVX2 指令集。有一个代码检查是否支持 AVX2,如果不支持则不执行。我无法直接访问此设备进行调试,以了解导致崩溃的确切代码。但现在我有两个假设:

  • 检查是否支持 AVX2 错误并在应返回 false 时返回 true 的代码
  • 即使检查返回错误的推测执行实际运行导致崩溃的 AVX2 代码

我已经替换/“修复”了检查代码作为主要假设,但测试人员仍然报告崩溃。所以我不确定那isAvx2Supported是假的。

检查是否支持 AVX2 的代码

使用 AVX2 的实际代码

崩溃报告说

崩溃的线程:43 队列(0x60400005b270)[16]

异常类型:EXC_BAD_INSTRUCTION (SIGILL) 异常代码:0x0000000000000001、0x0000000000000000

线程 43 崩溃:: Queue(0x60400005b270)[16] 0 0x000000010d54b06b findCharFast(char const*, unsigned long, char, unsigned int&) + 91

Thread 43 crashed with X86 Thread State (64-bit): rax: 0x00000000ffffffff rbx: 0x0000000000000000 rcx: 0x000070000982bbd0 rdx: 0x0000000000000000 rdi: 0x00007f9ac044fa0b rsi: 0x000000000000000d rbp: 0x000070000982bc00 rsp: 0x000070000982bbc8 r8: 0x0000000000000001 r9: 0x0000000000000001 r10: 0x000060c000334030 r11: 0xfffffffffffc0fde r12 : 0x0000000000000001 r13: 0x0000600000016fb0 r14: 0x00007f9ac044fa0b r15: 0x00007f9ac044fa18 rip: 0x000000010d54b06b rfl: 0x0000000000010246 cr2: 0x000000010d529cf0

0 投票
0 回答
35 浏览

cpu - 是否有 CPU 进行推测执行以虚拟化内存位置?

考虑在伪汇编中进行昂贵计算后寄存器的经典重用:

为了能够充分使用算术单元,执行单元可能会:

并并行:

其中 r2bis 是虚拟化(或重命名)的 r2 寄存器。

现在假设我们在寄存器较差的 CPU 中工作(或者我们有很多但它们已经被使用)并将数据放在某个临时堆栈位置:

是否存在地址已知的内存位置(如 (sp+C) 已经可以计算)被执行单元虚拟化以允许相同的两个执行并行进行的情况?

这种情况可能看起来很愚蠢,因为编译器的任务是在不受限制的堆栈空间上找到另一个位置(与非常受限制的寄存器空间不同)。但其他情况可能不会那么愚蠢,因为虚拟化内存可以允许条件分支的推测执行,该条件分支必须在内存中存储短期数据。这对于没有简单方法将对象字段放入寄存器的语言尤其重要,例如 Java,除了最简单的情况外:您必须排除“引用”(指针)转义以避免new动态分配并转向 Java类实例转换为 C++ 类自动实例(可以是堆栈分配的或寄存器中的)。this(然后即使是 C++ 也很难在简单平面类的看似简单的使用中没有真正的指针。)

0 投票
2 回答
625 浏览

cpu-architecture - 嵌套分支和推测执行会发生什么?

好的,所以我知道如果一个特定的条件分支有一个需要时间来计算的条件(例如内存访问),CPU 会假设一个条件结果并沿着该路径推测性地执行。但是,如果沿着这条路径弹出另一个缓慢的条件分支会发生什么(当然,假设第一个条件尚未解决并且 CPU 不能只提交更改)?CPU只是在推测里面推测吗?如果最后一个条件被错误预测但第一个条件不是,会发生什么?它只是一路回滚吗?

我在谈论这样的事情:

0 投票
1 回答
314 浏览

apache-spark - Spark推测的新任务有限制吗?

假设我在 Spark 中使用推测 = 运行工作true

如果一个任务(比如 T1)需要很长时间,Spark 会在另一个执行器上启动任务 T1(比如 T2)的副本,而不会杀死 T1。

现在,如果 T2 也比所有成功完成的任务的中位数花费更多的时间,Spark 会在另一个执行器上启动另一个任务 T3 吗?

如果是,这种新任务的产生是否有任何限制?如果不是,Spark 是否将自己限制为一项并行作业,并无限期地等待其中一项的完成?