0x01 Introduction
现代计算机使用多核 CPU,这些 CPU 包含多个通常跨计算单元共享的异构、互连组件。虽然这种资源共享为效率和成本带来了显着的好处,但它也为利用 CPU 微架构功能的新攻击创造了机会。其中一类攻击包括基于软件的隐蔽信道和侧信道攻击。通过这些攻击,攻击者利用访问特定共享资源时的意外效果(例如,时间变化)秘密地窃取数据(在隐蔽信道情况下)或推断受害者程序的秘密(在侧信道情况下)。这些攻击已被证明能够在许多情况下泄露信息。例如,许多基于缓存的侧信道攻击已被证明可以在云环境、网络浏览器和智能手机环境下发起。
幸运的是,近年来人们对此类攻击的认识也有所提高,并且可以采取应对措施来缓解此类攻击。首先,可以通过禁用同步多线程 (SMT) 和清理 CPU 微架构来缓解大量现有攻击在不同安全域之间进行上下文切换时的状态(例如,缓存)。其次,可以通过对最后一级缓存进行分区(例如,使用 Intel CAT)并禁用不同安全域的进程之间的共享内存来阻止基于跨核缓存的攻击。在这种限制性环境(例如 DRAMA)中仍然有效的唯一已知攻击存在于 CPU 芯片之外。
在本文中提出了第一个在采取上述对策后仍然有效的片上跨核侧信道攻击。攻击利用了环互联上的争用,环互联是许多现代英特尔处理器上不同 CPU 单元(内核、末级缓存、系统代理和图形单元)之间进行通信的组件。有两个主要原因使攻击具有独特的挑战性。首先,环互联是一个复杂的架构,具有许多活动部件。正如所展示的,了解这些经常没有记录的组件如何相互作用是成功攻击的必要先决条件。其次,通过环互联获取敏感信息比较困难。环不仅是一个基于竞争的信道——需要精确的测量能力来克服噪声——而且它只能看到由于空间粗粒度事件(如私有缓存未命中)引起的竞争。事实上在调查开始时,不清楚是否有可能通过这个信道泄露敏感信息。
为了应对第一个挑战,对处理环互联通信的英特尔的“sophisticated ring protocol”进行了彻底的逆向工程,揭示了哪些物理资源分配给了哪些环代理(内核、最后一级缓存片和系统代理)来处理不同的协议事务(从最后一级缓存加载和从 DRAM 加载),以及这些物理资源如何在多个进行中的事务数据包之间仲裁。了解这些细节对于攻击者衡量受害者程序行为是必要的。例如,发现该环将动态中的流量优先于新流量,并且它由两个独立的信道组成(每个信道有四个物理子环来为不同的数据包类型提供服务),为交错的代理子集提供服务。与最初的假设相反,这意味着两个代理以相同的方向,在重叠的环段上进行通信并不足以产生争用。将分析综合起来,第一次制定了两个或多个进程在环互联上相互竞争的充分必要条件,以及环微体系结构可能看起来与观察一致的合理解释。希望后者成为未来依赖 CPU 非内核的工作的有用工具。
接下来调查发现的安全隐患。首先利用以下事实:i) 当进程的负载受到争用时,它们的平均延迟大于常规负载的平均延迟,以及 ii) 了解逆向工程工作的攻击者可以通过这样的方式设置自己的负载为了保证与第一个进程的负载抗衡,在环互联上构建了第一个跨核隐蔽信道。隐蔽信道不需要共享内存,也不需要共享访问任何非内核结构(例如 RNG)。隐蔽信道从单个线程实现了高达 4.14 Mbps (518 KBps) 的容量,这比不依赖共享内存的所有先前信道都要快,并且与依赖共享内存的最先进的隐蔽信道处于同一数量级。
最后展示了利用环争用的侧信道攻击示例。第一次攻击从易受攻击的 RSA 和 EdDSA 实现中提取key位。具体来说,它滥用缓解措施来抢占调度缓存攻击,导致受害者的负载在缓存中丢失,在受害者计算时监视环争用,并使用标准机器学习分类器来消除痕迹和泄漏位。第二次攻击的目标是击键时间信息(可用于推断口令)。特别发现击键事件会导致攻击者可以检测到的环争用峰值,即使存在背景噪声也是如此。表明攻击实现可以高精度泄漏key位和击键时间。
0x02 Reverse Engineering the Ring Interconnect
在本节中着手了解现代英特尔 CPU 上环互联的微体系结构特征,重点关注攻击者在其上创建和监控竞争的必要和充分条件。此信息将作为隐蔽信道和侧信道的原语。
实验设置:在两台机器上运行实验,第一个使用 3.00GHz 的 8 核 Intel Core i7-9700(Coffee Lake)CPU。第二个使用 4.00GHz 的 4 核 Intel Core i7-6700K (Skylake) CPU。两个 CPU 都有一个包含的、集合关联的 LLC。 LLC 在 Skylake CPU 上每片有 16 路和 2048 组,在 Coffee Lake CPU 上每片有 12 路和 2048 组。两个 CPU 都有一个 8 路 L1 64 组和一个 4 路 L2 1024 组。使用带有内核 4.15 的 Ubuntu Server 16.04 进行实验。
A.推断环形拓扑
监测环互联:以先前工作为基础创建了一个监控程序,该程序可以测量每个内核对不同 LLC 切片的访问时间。设WL1、WL2 和WLLC 分别为L1、L2 和LLC 的关联性。给定一个核c、一个 LLC 切片索引 s 和一个 LLC 缓存集索引 p,程序如下工作:
1.把自己固定到给定的 CPU 核 c。
2.分配≥ 400 MB 内存的缓冲区。
3.遍历缓冲区,寻找映射到所需切片 s 和 LLC 缓存集 p 的 WLLC 地址,并将它们存储到监控集中。切片映射使用硬件性能计数器。这一步需要 root 权限,但稍后将讨论如何在非特权访问的情况下计算切片映射。
4.遍历缓冲区,寻找映射到与监控集地址相同的 L1 和 L2 缓存集的 WL1 地址,但不同的 LLC 缓存集(即,LLC 缓存集索引不是 p)并存储将它们放入称为驱逐集(eviction set)的集合中。
5.对监控集的每个地址进行加载。在这一步之后,监控集的所有地址都应该在 LLC 中命中,因为它们的数量等于 WLLC。其中一些也会进入私有缓存。
6.通过访问驱逐集的地址,从私有缓存中驱逐监控集的地址。确保监控集的地址缓存在 LLC 中,而不是私有缓存中。
7.使用时间戳计数器 (rdtsc) 对来自监控集地址的负载进行计时,并记录测量的延迟。这些加载将在私有缓存中丢失并在 LLC 中命中。因此,它们将需要穿过环互联。根据需要重复步骤 6-7 以收集所需数量的延迟样本。
结果:在每个 CPU 内核上运行监控程序,并从每个不同的 LLC 切片收集 100,000 个负载延迟样本。Coffee Lake CPU 的结果绘制在上图中。这些结果证实了两个 CPU 上环互联的逻辑拓扑与下图中所示的线性拓扑相匹配,即:当负载必须在环互连上移动较长的距离时,LLC的负载延迟更大。
一旦攻击者知道此拓扑结构和相应的负载延迟,他们将能够通过计时访问它们所需的时间并将延迟与前图结果进行比较,将任何地址映射到其切片。到目前为止,监控延迟将可能的切片从 n 缩小到 2。为了精确定位一条线映射到的确切切片,攻击者可以从 2 个内核进行三角测量。这不需要root访问权限。先前的工作探索了攻击者如何使用这些知识来降低寻找驱逐集的成本,以及防御者如何增加页面着色中的颜色数量。
B.了解环上的争用
在什么情况下两个进程可以在环互联上竞争?为此,对英特尔处理环互联通信的“sophisticated ring protocol”进行了逆向工程。使用两个进程,一个接收方和一个发送方。
衡量竞用:接收方是前文中描述的监控程序的优化版本,由于以下观察,它跳过了第 4 步和第 6 步(即不使用驱逐集):因为在CPU 上 WLLC > WL1 和 WLLC > WL2 ,并非监控集的所有 WLLC 地址都可以在任何给定时间放入 L1 和 L2。例如,在Skylake 机器上,WLLC = 16 和 WL2 = 4。考虑访问监控集的前 4 个地址的场景。这些地址适合私有缓存和 LLC。然而,观察到访问监控集的剩余 12 个地址会从私有缓存中驱逐前 4 个地址。因此,当在下一次迭代中再次加载第一个地址时,仍然只命中 LLC。使用这个技巧,如果遍历监控集并按顺序访问它的地址,总是可以从 LLC 加载。为了确保按顺序访问地址,使用指针追踪来序列化加载,为了减少因外部噪声而遭受 LLC 驱逐的可能性,接收方将监控集的 WLLC 地址均匀分布在两个 LLC 缓存集(在同一切片内)。最后,为了放大争用信号,接收方一次执行 4 个连续加载,而不是 1 个。 接收方的大部分代码如下面List 1所示。
创造争用:发送方旨在通过用流量“轰炸”环互联上的特定段来创建对它的争用。此流量从其内核发送到位于环上的不同 CPU 组件,例如 LLC 切片和系统代理。为了针对特定的 LLC 切片,发送方基于与接收方相同的代码。但是,它既不计时也不序列化其负载。此外,为了产生更多流量,它使用具有 2 个 WLLC 地址的更大监控集(均匀分布在两个 LLC 缓存集上)。为了针对系统代理 (SA),发送方使用了一个更大的监控集,其中包含 N > 2 个 WLLC 地址。由于并非所有这 N 个地址都适合两个 LLC 缓存集,因此这些加载将在缓存中丢失,从而导致发送方与内存控制器(在 SA 中)进行通信。
数据收集:使用接收方和发送方来收集有关环争用的数据。对于第一组实验,将发送方配置为从单个 LLC 切片(没有 LLC 未命中)连续加载数据。对于第二组实验,将发送方配置为始终在其来自目标 LLC 切片的负载上发生未命中。为了防止意外的额外噪音,禁用预取器并将发送方和接收方配置为针对不同的缓存集,以便它们不会通过传统的基于驱逐的攻击进行干扰。将发送方的内核称为 Sc,其目标切片为 Ss,接收方的内核为 Rc,其目标切片为 Rs。对于 Sc、Ss、Rc 和 Rs 的每个组合,测试同时运行发送方和接收方是否会影响接收方测量的负载延迟。然后,将结果与禁用发送方的基线进行比较。当接收方测量的平均负载延迟大于基线时,存在争用。上图显示了第一个实验的结果,此时发送方总是在 LLC 中命中。当发送方总是在 LLC 中丢失时,两个数字均指 Coffee Lake。4 核 Skylake 机器的结果是 8 核 Coffee Lake 机器的子集(Rc < 4∧Rs < 4∧Sc < 4∧Ss < 4)。
当发送方在 LLC 中命中时的观察:首先,当 Ss = Rs 时总是存在争用,而不管发送方和接收方相对于 LLC 切片的位置如何。这种系统性的“切片争用”行为在图中用星标记,很可能是由于 i) 发送方和接收方的负载填满了切片的请求队列( ,从而导致加载请求的处理时间延迟,以及 ii) 发送方和接收方的负载使共享切片端口的带宽饱和(最多可以提供 32 B/周期,或每个缓存线的一半)循环,从而导致将缓存行发送回内核的延迟。
当代理用请求轰炸LC切片时,从同一切片加载的其他代理会观察到延迟。
其次,当 Rc = Rs 时,存在竞争且仅当 Ss = Rs 时。也就是说,从 Rc = i 到 Rs = i(内核到home切片流量)的接收方负载永远不会与从 Sc != i 到 Ss != i(跨环流量)的发送方负载竞争。这证实了每个内核 i 都有一个“home”切片 i,除了共享的内核/切片环停止之外,它不占用环互联上的任何链路。
环站可以同时服务核心到home切片流量和跨环流量。
第三,排除切片争用(Ss != Rs),如果发送方和接收方执行相反方向的加载,则永远不会发生争用。例如,如果接收方的负载从“左”到“右”(Rc < Rs)和发送方的负载从“右”到“左”(Sc > Ss),则没有争用,反之亦然。右/左方向上的载荷不与左/右方向上的载荷相抗衡这一事实证实了环有两个物理流,每个方向一个。
环站可以同时服务于相反方向的跨环流量。
第四,即使发送方和接收方的负载沿同一方向传播,如果 Sc 和 Ss 之间以及 Rc 和 Rs 之间的环互联段不重叠,也不会发生争用。例如,当 Rc = 2 且 Rs = 5 时,如果 Sc = 0 且 Ss = 2 或 Sc = 5 且 Ss = 7,则不存在争用。这是因为环互联上的负载流量仅通过之间的最短路径传输内核的环挡和切片的环挡。如果发送方的段与接收方的段不重叠,则接收方将能够使用其段上的全部总线带宽。
通过环互连的非重叠段的环流量不会引起争用。
上述观察将缩小到发送方和接收方沿相同方向并通过环的重叠部分执行负载的情况。在环互联由四个环组成:1)请求,2)确认,3)监听和 4)数据环。虽然众所周知 64 B 高速缓存线作为两个数据包通过 32 B 数据环传输,但很少披露: (i) 哪些类型的数据包通过其他三个环以及 (i) 如何传输数据包在负载事务期间流经四个环。英特尔在 曾回答了 (i),其中解释了单独的环分别用于 1) 读/写请求 2) 全局观察和响应消息,3) 监听内核和 4) 数据填充和回写。此外,英特尔在插图中阐明了 (ii),该插图解释了 LLC 命中事务的流程:事务以从内核传输到目标 LLC 切片的请求数据包开始(hit flow 1: core→slice, request);收到这样的数据包后,切片检索请求的缓存行;最后,它向内核发送回全局观察 (GO) 消息,后跟缓存行的两个数据包(hit flow 2: slice→core, data and acknowledge)。然而重要的是,数据表明在同一方向上执行负载并与接收方共享环互联的一部分并不是发送方在环互联上产生争用的充分条件。
环互连分为四个独立且功能分离的环。 LLC 负载使用请求环、确认环和数据环。
首先,如果接收方的流量包含环互联的发送方流量(即 Rc < Sc ≤ Ss < Rs 或 Rs < Ss ≤ Sc < Rc),则接收方不会看到任何争用。例如,当 Rc = 2 且 Rs = 5 时,如果 Sc = 3 且 Ss = 4,就看不到争用。这种行为是由于环互联上的分布式仲裁策略所致。英特尔用一个类比来解释它,将环比作一辆装有货物的火车,其中每个环槽类似于没有货物的车厢。为了在环上注入一个新的数据包,环代理需要等待一个空闲的车厢。该策略确保环上的流量永远不会被阻塞,但它可能会延迟其他代理注入新流量,因为环上已有的数据包优先于新数据包。为了在环上创建争用,发送方需要将其流量注入该环,以便它优先于接收方的流量,这只有在其数据包在接收方的上游站点注入时才会发生。
环站总是优先考虑已经在环上的流量,而不是从其代理进入的新流量。当现有的环上流量延迟了新环流量的注入时,就会发生环争用。
其次,即使发送方的流量优先于接收方的流量,接收方也并不总是观察到争用。让集群 A = {0,3,4,7} 和 B = {1,2,5,6}。当发送方在请求环上(on the core→slice traffic)具有优先级时,如果 Ss 与 Rs 在同一个集群中,则存在争用。类似地,当发送方在数据/确认环上(on the slice→core traffic)具有优先权时,如果 Sc 与 Rc 位于同一集群中,则会发生争用。如果发送方在所有环上都有优先权,观察上述条件的并集。这一观察结果表明,每个环可能有两个“车道”,并且该环停止将流量注入不同的车道,具体取决于其目的地代理的集群。作为 slice→core流量的例子,让Rc = 2(Rc ∈ B)和Rs = 5。在这种情况下,从Rs到Rc的流量在与内核集群B对应的车道上行驶。当Sc = 3(Sc ∈ B) A) 且 Ss = 7,从 Ss 到 Sc 的流量在与内核集群 A 对应的车道上行驶。因此这两个流量流不竞争。但是,如果将 Sc 改为 Sc = 1 (Sc ∈ B),那么从 Ss 到 Sc 的流量也会在与内核集群 B 对应的车道上行驶,从而与接收方竞争。
每个环有两条车道。 前往 A = {0,3,4,7} 中切片的流量在一条车道上行驶,而前往 B = {1,2,5,6} 中切片的流量在另一条车道上行驶。 类似地,去往 A = {0,3,4,7} 中内核的流量在一条车道上行驶,而去往 B = {1,2,5,6} 中内核的流量在另一条车道上行驶。
最后观察到发送方仅在slice→core 流量上具有优先级时引起的争用量大于其仅在core→slice上具有优先级时引起的争用量。这是因为 i)slice→core 由确认环和数据环流量组成,在两个环上延迟接收方,而 core→slice 流量仅在一个环(请求环)上延迟接收方和 ii)slice→core 数据流量本身每个负载包含 2 个数据包,它们在其环上占据更多插槽(“车厢”),而请求流量可能包含 1 个数据包,仅占用其环上的一个插槽。此外,当发送方的优先级高于slice→core和core→slice流量时,争用量最大。
数据环上的流量比请求环上的流量产生更多的争用。 此外,当流量同时在多个环上竞争时,竞争会更大。
综上所述,包含两种类型的争用:切片争用(带有星的单元格)和环互联争用(灰色单元格)。后者发生在发送方的请求流量延迟接收方的请求流量注入请求环,或者发送方的数据/GO 流量延迟接收方的数据/GO 流量注入数据/确认环时。为此,发送方的流量需要与接收方的流量在同一车道、重叠段和同一方向上行驶,并且必须从接收方的流量上游注入。正式地,当发送方在 LLC 缓存中命中时,争用发生在以下条件下:
当发送方错过 LLC 时的观察:现在报告对第二个实验结果的观察结果(如下图所示),当发送方在 LLC 中未命中时。请注意,接收方的负载仍在 LLC 中。
首先,仍然观察到与发送方在 LLC 中命中时观察到的相同的切片争用行为。这是因为,即使请求的缓存行不存在于 Ss 中,加载请求仍然需要首先从 Sc 传输到 Ss,因此仍然有助于填满 LLC 切片的请求队列,从而造成延迟 。此外,当 Rc、Rs、Sc 和 Ss 满足先前的请求环竞争条件时,发送方的请求(miss flow 1: core→slice, request)仍然与接收方的core→slice请求流量竞争。
LLC 无法满足的加载请求仍会通过其目标 LLC 切片。
其次,英特尔指出,在缓存未命中的情况下,LLC 切片通过请求到达的同一请求环(在术语中为同一请求环信道)将请求转发到系统代理(SA)。也就是说,LLC 未命中事务包括从 Ss 到 SA 的第二个请求流(miss flow 2: slice→SA, request),数据支持此流程的存在。当接收方的负载从右向左移动时(Rc > Rs),Ss > Rc,并且发送方和接收方共享各自的信道(Rs 与 Ss 在同一个集群中),观察到了争用。例如,当 Rc = 5,Rs = 2 (Rs ∈ B) 和 Ss = 6 (Ss ∈ B) 时,发送方从 Ss 到 SA 的请求与接收方从 Rc 到 Rs 的请求竞争。这一事实的一个微妙含义是 SA 的行为与其他环代理类型(切片和内核)不同,因为它可以在请求环的任一信道上接收请求流量。发现 Ss 只是将请求(作为新流量)转发到与它从 Sc 接收请求相同的信道上的 SA,受通常的仲裁规则约束。
进行了两个额外的观察:i) 由slice→SA 流引起的争用量小于由内核→切片流引起的争用量,没有关于为什么会这样的假设。 ii) 在特殊情况下 Ss = Rc(在示例中 Ss = 5)与 Ss > Rc 的情况相比,争用略少。这可能是因为,当要求其内核和切片都注入新流量时,环停止采用循环策略而不是优先考虑任何一方。英特尔在最近的一项专利中使用了这样的协议。
如果未命中,LLC 切片会将请求(作为新流量)转发到它到达的同一通道上的系统代理。 当一个切片和它的主核都试图将请求流量注入同一通道时,它们的环站采用公平的循环仲裁策略。
除了将请求转发给SA之外,切片Ss还通过确认环(miss flow 3:slice→core, acknowledge)向请求的core Sc响应一个响应包。在收到来自 Ss 的请求后,SA 检索数据并将其发送到请求的内核 Sc,其前面是 GO 消息(miss flow 4: SA→core, data and acknowledge)。当 Sc 收到请求的数据时,事务完成。为了保持包容性,SA 还通过数据环向 Ss 发送一份单独的数据副本(miss flow 5: SA→slice, data)。在下图中总结了本部分讨论的五个流程。
未命中流 4(SA→core, data/acknowledge)的存在由当接收方的负载从右到左(Rc > Rs),Sc > Rs 并共享各自的数据/确认环时存在争用支持与发送方的车道。例如,当 Rc = 7 (Rc ∈ A)、Rs = 2、Sc = 3 (Sc ∈ A) 和 Ss = 4 时存在争用。SA 位于最左边的环站,这意味着SA 注入的流量总是优先于 Rs 注入的接收方流量。为了证实假设,即 SA 直接向 Sc(而不是通过 Ss)提供数据/确认流量,用不同的 Sc 和固定的 Ss = 7 对发送方的单个 LLC 未命中的负载延迟进行计时。如果假设成立,期望一个恒定的延迟,因为无论 Sc 是什么,事务都需要从 Sc 到环站 7,从环站 7 到 SA,从 SA 到 Sc,无论 Sc 是相同的距离;否则,希望看到随着 Sc 增加而减少的延迟。测量了固定延迟(248±3 个周期),证实了假设。
系统代理直接向发出负载的内核提供数据和全局观察消息。
在之前观察到数据/确认环争用与在 LLC 中命中的发送方的情况下,争用的存在支持了未命中流 3(slice→core, acknowledge)的存在。例如,当 Rc = 2 (Rc ∈ B)、Rs = 6、Sc = 5 (Sc ∈ B) 和 Ss = 7 时,观察到争用。 然而,当发送方在 LLC 中未命中时,Ss 不会发送任何数据流量到 Sc(因为看到数据直接由 SA 提供给内核)。观察到的争用必须是由于 Ss 将流量注入确认环。实际上,这种仅确认流引起的争用量既小于数据/确认流引起的争用量,也等于内核→切片请求流引起的争用量,这表明与请求流相似,未命中流3 可能占据其环上的一个插槽。英特尔的一项专利表明,当请求在 LLC中未命中时,未命中流 3 可能包含由 Ss 传输到 Sc 的“LLCMiss”消息。唯一剩下的问题(目前无法回答)是什么时候发生未命中流 3:何时检测到未命中或何时重新填充数据——但这两种选择都会导致相同的争用。
如果发生未命中,未命中的 LLC 切片仍会通过确认环将响应数据包发送回请求内核。
最后,当接收方的负载从右到左(Rc > Rs),Ss > Rs 并与发送方共享各自的信道时,存在争用支持未命中流 5(SA→slice,data)的存在。但是,发现 SA→slice流量的争用规则存在细微差别。与 SA→core情况不同,接收方和发送方由于相同类型(数据和确认)的流量被送往相同类型(内核)的代理而发生竞争,现在有相同类型的接收方和发送方流(数据)指定给不同类型的代理(分别是内核和切片)。在前一种情况下,看到如果接收方流和发送方流的目标环代理在同一个集群中,则它们共享信道。在后一种情况下(仅在这种情况下发生),观察到如果两个流的目标环代理位于不同的集群中,则它们共享信道。这表明,正如在上表中总结的那样,用于与不同集群通信的信道可能会根据目标代理类型进行翻转。对miss flow 5进行了另外两个观察。首先认为SA→slice流量只包括数据和没有确认流量,因为它引起的争用量略小于SA→内核流量引起的争用量。其次,发现 SA→slice流量与 SA→core流量分开发生。例如,如果来自 SA 的数据必须首先在 Sc 处停止,那么当 Rc = 5 (Rc ∈ B)、Rs = 2、Sc = 4、Ss = 3 (Ss ∈ A) 时,观察到的争用就不会发生。此外,当发送方在 SA→slice 和 SA→core 流量上竞争时,竞争大于单个竞争,这进一步支持了两个流的独立性。
如果发生丢失,系统代理会向丢失的 LLC 切片提供单独的数据副本,以保持包容性。 用于向一个集群的 LLC 切片发送数据流量的环形通道与用于向相对集群的核心发送数据流量相同。
总而言之,当发送方在 LLC 中未命中时,由于处理 LLC 未命中事务所需的额外流量,与等式 1 相比会出现新的环争用情况。形式化地,争用发生在 iff:
其他注意事项:现在对结果提供额外的观察。首先,竞争量与发送方和接收方之间重叠段的长度不成正比。这是因为,正如所看到的,竞争取决于在尝试注入新流量时经过接收方环站的完整“车厢”的存在,而不是这些车厢的目的地有多远。
其次,当多个发送方同时与接收方的流量竞争时,竞争量会增加。这是因为多个发送方在环上填充了更多时隙,从而进一步延迟了接收方环停止注入其流量。例如,当 Rc = 5 且 Rs = 0 时,运行一个 Sc = 7 和 Ss = 4 的发送方以及一个 Sc = 6 和 Ss = 3 的发送方会比单独运行任一发送方产生更多的争用。第三,启用硬件预取器在某些情况下会放大争用,并在某些新情况下引起争用(如果预取器关闭,发送方将不会与接收方争用)。这是因为预取器导致 LLC 或 SA 将额外的缓存线传输到内核(可能映射到请求线之一之外的其他 LLC 片),从而可能在多个信道上填充更多的环形槽。英特尔自己指出,预取器会干扰正常加载并增加加载延迟。将正式建模由预取器引起的额外争用模式以供未来工作。
最后强调,构建的竞争模型完全基于对 CPU 收集的数据的观察和假设。提供的一些解释可能是不正确的。然而,主要目标是让模型有用,在接下来的几节中,将证明它足以构建攻击。
安全影响:呈现的结果带来了一些重要的收获。首先,对关于环互联是否容易发生争用的问题给出了肯定的答案。其次,在环互联上监视争用的接收方进程可以了解有关运行在同一主机上的单独发送方进程的哪些类型的信息。通过将自己固定到不同的内核并从不同的切片加载,接收方可以区分发送方空闲的情况和执行在其私有缓存中未命中并由特定 LLC 切片服务的加载的情况。了解另一个进程从哪个 LLC 切片加载也可能会揭示有关加载的物理地址的一些信息,因为地址映射到的 LLC 切片是其物理地址的函数。此外,虽然考虑了这些场景,但环竞争可用于区分发送方行为的其他类型,例如内核和其他 CPU 组件(例如,图形单元和外围设备)之间的通信。然而,重要的是,对于这些任务中的任何一个,接收方都需要自行设置,以便预计会发生与发送方的争用。等式 1 和 2 通过揭示流量可以在环互联上竞争的必要条件和充分条件使这成为可能。
0x03 Cross-core Covert Channel
使用前文的发现来构建第一个跨核隐蔽信道,以利用环互联上的争用。隐蔽信道协议类似于传统的基于缓存的隐蔽信道,但在例子中,发送方和接收方不需要共享缓存。发送方的基本思想是通过在环互联上创建争用来传输位“1”,并通过空闲传输位“0”,从而不产生环争用。同时,接收方计算负载(使用List 1 的代码),这些负载通过环互联的一段,由于发送方的负载而容易发生争用(此步骤需要使用前文中的结果)。因此,当发送方发送“1”时,接收方会经历加载延迟。为了区分“0”和“1”,接收方可以简单地使用平均负载延迟:较小的负载延迟分配给“0”,较大的负载延迟分配给“1”。为了同步发送方和接收方,使用共享时间戳计数器,但信道也可以扩展为使用其他不依赖公共时钟的技术。
为了使隐蔽信道更快,首先将接收方配置为使用环互联的一个短段。由于较小的加载延迟,这允许接收方在单位时间内发出更多加载,而不会影响发送方创建争用的能力。其次,将发送方设置为在 LLC 中命中,并使用 Sc 和 Ss 的配置,根据等式 1保证在其内核→切片流量和切片→内核流量上与接收方竞争。竞争两个流允许发送方放大 0(无竞争)和 1(竞争)之间的差异。第三,保留预取器,因为看到它们使发送方能够创建更多争用。
创建了一个隐蔽信道的概念验证实现,其中发送方和接收方是单线程的,并同意固定的位传输间隔。上图显示了由 Coffee Lake 3.00 GHz CPU 上的接收方测量的负载延迟,假设接收方和发送方配置分别为 Rc = 3、Rs = 2 和 Sc = 4、Ss = 1。对于该实验,发送方以 3,000 个周期的传输间隔(相当于 1 Mbps 的原始带宽)传输交替的 1 和 0 序列。结果表明,1(峰)和0(谷)是明显可区分的。为了评估在不同传输间隔下实现的性能和稳健性,使用信道容量度量。该度量是通过将原始带宽乘以 1-H(e) 来计算的,其中 e 是比特错误的概率,H 是二元熵函数。下图显示了Coffee Lake CPU 上的结果,在给定 750 个周期的传输间隔(相当于 4 Mbps 的原始带宽)的情况下,信道容量峰值为 3.35 Mbps (418 KBps)。这是迄今为止不依赖共享内存的所有现有跨核隐蔽信道中最大的隐蔽信道容量。通过使用 727 个周期的传输间隔,在 Skylake 4.00 GHz CPU 上实现了 4.14 Mbps (518 KBps) 的更高容量。
最后注意到,虽然数字代表了真实的、可重复的端到端容量,但它们是在没有背景噪音的情况下收集的。嘈杂的环境可能会降低隐蔽信道的性能,并且需要在传输中包含额外的纠错码,目前没有考虑到这些。
0x04 Cross-core Side Channels
在本节中展示了两个利用环互联上的争用的侧信道示例。
基本理念:在两个攻击中,都使用前文中描述的技术(参见List 1)来实施攻击。攻击者(接收方)发出通过环互联固定段传输的负载并测量它们的延迟。将每个测量的负载延迟称为一个样本,并将许多样本的集合(即攻击者/接收方的一次运行)称为跟踪。如果在攻击期间受害者(发送方)执行满足等式 1 和 2 条件的内存访问以应对攻击者的负载,则攻击者将测量更长的负载延迟。通常,不知情的受害者访问的切片将均匀分布在 LLC中。因此,受害者的某些访问很可能会与攻击者的负载相抗衡。如果攻击者测量的延迟可以归因于受害者的秘密,则攻击者可以将它们用作侧信道。
威胁模型和假设:假设 SMT 关闭并且基于多核缓存的攻击是不可能的(例如,由于对 LLC 进行分区并禁用跨安全域的共享内存)。对加密代码的攻击还假设:i) 管理员已将系统配置为在上下文切换时清除受害者的缓存占用空间(以阻止基于缓存的抢占式调度攻击)和 ii) 攻击者可以观察到受害者的多次运行。假设攻击者了解受害者机器的争用模型,并且可以在受害者机器上运行非特权代码。
A.对加密代码的侧信道攻击
第一次攻击针对的是遵循如下算法 1 伪代码的受害者,其中 E1 和 E2 是对某些用户输入(例如密文)执行不同操作的独立函数。这是密码原语的有效实现中的一种常见模式,在许多现有的侧信道攻击中被利用,例如 RSA、El Gamal、DSA、ECDSA和 EdDSA。
考虑受害者循环的第一次迭代,现在假设受害者从冷缓存开始,这意味着它的代码和数据没有被缓存(没有事先执行)。当受害者第一次执行 E1 时,它必须通过环互联将 E1 使用的代码和数据字加载到其私有缓存中。那么,有2种情况:第一个key位为0时为1。当第一位为0时,受害者的代码在E1之后跳过对E2的调用,并通过再次调用E1跳转到下一次循环迭代。在第二次 E1 调用中,E1 的词已经在受害者的私有缓存中,因为它们刚刚被访问过。因此,在第二次调用 E1 期间,受害者不会将流量发送到环互联上。相反,当第一位为 1 时,受害者的代码会在第一个 E1 之后立即调用 E2。当第一次调用 E2 时,它的代码和数据字在缓存中丢失,加载它们需要使用环互联。然后攻击者可以通过检测 E2 是否在 E1 之后执行来推断第一位是 0 还是 1。 E1 执行后的争用峰值意味着 E2 已执行且第一个secret位为 1,而 E1 执行后没有争用峰值意味着对 E1 的调用之后是对 E1 的另一个调用且第一个secret位为 0。
可以通过让攻击者使用抢占式调度技术来让攻击者中断/恢复受害者,从而将这种方法推广到泄漏多个key位。令 TE1 是受害者从冷缓存开始执行 E1 所花费的中值时间,TE1+E2 是受害者从冷缓存开始执行 E1 和 E2 所花费的中值时间。完整的攻击过程如下:攻击者启动受害者并让它运行 TE1+E2 周期,同时监视环互联。在 TE1+E2 循环之后,攻击者会中断受害者并分析收集到的跟踪,以使用上述技术推断出第一个secret位。中断受害者会导致上下文切换,在此期间受害者的缓存在将控制权交给攻击者之前被清除(参见威胁模型)。作为副作用,这会将受害者带回冷缓存状态。
如果跟踪显示第一个secret位是 1,则攻击者恢复受害者(现在处于第二次迭代的开始)并让它运行 TE1+E2 多个周期,重复上述过程以泄漏第二位。如果跟踪显示第一个secret位为 0,则攻击者停止受害者(或让它完成当前运行),从头开始重新启动,让它运行 TE1 周期,然后中断它。受害者现在将处于第二次迭代的开始,攻击者可以重复上述过程以泄漏第二位。攻击者重复这个操作,直到所有的key位都被泄露。在最坏的情况下,如果所有的key位都是零,攻击需要受害者的运行次数与key的位数一样多。在最好的情况下,如果所有的key位都是 1,那么它只需要运行一次受害者。
执行:对 RSA 和 EdDSA 的攻击实施了概念验证 (POC)。POC 通过允许攻击者与受害者循环的目标迭代同步来模拟抢占式调度攻击。此外,POC 通过在执行目标迭代之前刷新受害者的内存来模拟缓存清理。它通过在构成受害者映射页面的每个缓存行上调用 clflush 来实现这一点(在 / proc/ [pid]/ maps 中可用)。POC 考虑了上述最坏的情况,受害者每次运行都会泄漏一个key位。为了简化从每个结果跟踪推断key位的过程,POC 使用支持向量机分类器 (SVC)。请注意,虽然考虑的 RSA 和 EdDSA 实现已经知道容易受到侧信道的影响,但本文是第一个证明它们专门通过环互联信道泄漏的。
结果:对于 RSA,的目标是 libgcrypt 1.5.2 的 RSA 解密代码,它在其模幂函数 _gcry_mpi_powm 中使用依赖于秘密的平方和乘法方法。该模式匹配算法 1 中的一个,其中 E1 代表平方阶段,无条件执行,E2 代表乘法阶段,仅对key的 1 值位有条件地执行。
在内核 Rc = 2 上配置攻击者(接收方),从 Rs = 1 定时加载,并试验不同的受害者(发送方)内核 Sc。下图a 显示了当 Sc = 5 时,攻击者收集到的跟踪以泄漏受害者的一个key位。为了更好地可视化 0 位和 1 位之间的差异,跟踪对受害者的 100 次运行进行了平均。正如预期的那样,观察到两条轨迹都从峰值开始,对应于对 E1 的第一次调用,通过环互联从存储器控制器加载其代码和数据字。然而,只有当secret位为 1 时,才会在图的右侧观察到一个额外的峰值。这个额外的峰值对应于对 E2 的调用。当在其他内核以及Skylake 机器上运行受害者时,得到同样可区分的模式。
为了训练分类器,收集了一组 5000 条轨迹,其中一半是受害者在 0 位上运行,另一半在 1 位上运行。使用来自每个轨迹的前 43 个样本作为输入向量,并使用相应的 0 或 1 位作为标签。然后将向量集随机分成 75% 的训练集和 25% 的测试集,并训练分类器区分这两个类。分类器在预取器打开的情况下达到 90% 的准确度,在预取器关闭的情况下达到 86%,这表明攻击者在受害者迭代期间测量的单个负载延迟跟踪可以高精度泄漏该迭代的secret key位。
EdDSA 的结果:目标是 libgcrypt 1.6.3 的 EdDSA Curve25519 签名代码,它在其椭圆曲线点标量乘法函数 _gcry_mpi_ec_mul_point 中包含一个秘密相关代码路径。在此函数中,加倍阶段表示 E1,无条件执行,加法阶段表示 E2,仅在key的 1 值位(即标量)上有条件地执行。
在上图b 中报告了使用与 RSA 攻击相同的设置进行一点泄漏的结果。两条曲线都从对应于第一次调用 E1 的峰值开始。然而,只有当secret位为 1 时,才会在图的右侧观察到一个额外的峰值。这个额外的峰值对应于对 E2 的调用。在其他内核以及 Skylake 上获得了与受害者相似的模式。像针对 RSA 攻击所做的那样训练分类器,除了单个向量现在包含 140 个样本。分类器在预取器打开时达到 94% 的准确率,在预取器关闭时达到 90%。
B.击键定时攻击
第二个侧信道攻击会泄露用户键入的按键时间。也就是说,攻击者的目标是检测何时发生击键并提取精确的击键间时间。此信息是敏感的,因为它可用于重建键入的单词(例如,口令)。这是首次将基于竞争的微架构信道用于击键计时攻击。
攻击基于以下观察:处理击键是一个复杂的过程,需要多个硬件和软件堆栈层的交互,包括南桥、各种 CPU 组件、内核驱动程序、字符设备、共享库和用户空间专业空间进程。先前的工作表明,单独的终端仿真器会产生毫秒级的按键处理延迟(即数百万个周期)。此外,即使处理单个击键也涉及执行和访问大量代码和数据。因此假设,在其他空闲的服务器上,击键处理可能会导致环争用中可检测到的峰值。
执行:为了验证假设,开发了一个简单的控制台应用程序,它在循环中调用 getchar() 并记录每次按键发生的时间,作为基本事实。考虑两种情况:i)在本地终端上打字(使用物理键盘输入),以及 ii)通过交互式 SSH 会话打字(使用远程输入)。
结果:上图显示了攻击者在 SSH 键入场景中在Coffee Lake 机器上收集的跟踪,在应用具有 3000 个样本的窗口的移动平均之后。报告了下图a中单个击键轨迹的放大版本。第一个观察结果是,当击键发生时,观察到一种非常明显的环争用模式。在输入“To be, or not to be”独白的前 100 个字符时运行攻击,在所有按键事件上观察到这种模式,零误报和零漏报。此外,在记录击键后的 1 毫秒(3×106 个周期)内始终可以很好地观察到环争用峰值,这是先前工作用于区分按下的键的推理算法所需的精度。当在本地终端和 Skylake 上键入按键时,得到了类似的结果。此外,在后台运行stress -m N 时测试了攻击,这会产生 N 个线程,在系统上生成合成内存负载。当 N ≤ 2 时,击键时环竞争的时间模式仍然很容易与背景噪声区分开来。 然而,随着负载的增加(N > 2),击键开始通过简单地使上图的移动平均值变得更难识别,并且当 N > 4 时,它们开始变得几乎完全无法与背景噪声区分开来。
在击键时观察到的延迟峰值是由环争用(而不是例如缓存逐出或中断)引起的,原因有几个。首先,由击键争用引起的延迟差异与前文中测量的相同。其次观察到,尽管击键处理会在所有切片上产生争用,但当攻击者监视时,延迟峰值更为明显引起更多争用的环形段(即带有最多灰色单元格的表格)。例如,当 Rc = 0 和 Rs = 7 时,击键时的峰值小于大多数其他配置。这是因为在这种配置中,攻击者总是在请求环(Rc 的上游没有其请求流量可以延迟 Rc 的内核)和数据/确认环(Rs 的上游没有切片/SA)上拥有优先权。其数据/确认流量可能会延迟 Rs 的流量)。因此认为在这种情况下发生的唯一争用是切片争用。第三,当尝试用攻击者计时 L1 命中而不是 LLC 命中重复实验时,没有看到击键时的延迟峰值。
0x05 Conclusion
在本文中介绍了对环互联的侧信道攻击。 对环互联的协议进行了逆向工程,以揭示两个进程引起环争用的条件。 使用这些发现构建了一个容量超过 4 Mbps 的隐蔽信道,这是迄今为止不依赖共享内存的跨核信道的最大容量。 还表明,环争用的时间趋势可用于从易受攻击的 EdDSA/RSA 实现中泄漏key位以及用户键入的击键时间。 已向英特尔披露了本研究的结果。