summaryrefslogtreecommitdiff
path: root/chap/chap2.tex
blob: 3224d22cda5dc6f9d7eddea0c6436e5bbadec9f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
% Copyright (c) 2014,2016 Casper Ti. Vector
% Public domain.

\chapter{Meltdown和Spectre攻击}\label{sec:attack}

本章首先介绍侧信道攻击,之后对已有的 Meltdown 和 Spectre 攻击的各种变
体进行分类讲解,最后简单地介绍已有攻击的其他使用形式。

\section{侧信道攻击}

侧信道攻击是利用计算的过程对环境产生的影响,从而获取秘密数据的技术。
1996年,Paul Kocher 发现通过对私钥的操作进行计时,可以找出
Diffie-Hellman,RSA 等密码的私钥。\supercite{TimingAttack} 这是最早的
侧信道攻击的研究。之后研究者发现了更多侧信道,如功耗
\supercite{MOP2010}、电磁辐射\supercite{EMpower}、温度
\supercite{hutter}、噪声\supercite{acoustic}等。

侧信道攻击的一个用途是用于构造隐蔽信道(covert channel)。隐蔽信道是指
在系统安全策略定义之下,不被允许传输数据的双方,用于传输数据的信道。

现代计算机系统采用多种优化手段,优化可以作用于处理的数据的值、数据的位
置、数据存放位置的访问频率等,攻击者可以通过这些优化产生的效果,推断出
计算机系统处理的秘密数据的值。基于软件的微架构侧信道攻击
\supercite{gruss}利用微架构优化造成的时间区别,这种攻击不需要物理访问
计算机系统,只需要在系统上运行代码。

高速缓存计时攻击是一种重要的侧信道攻击的方式。当高速缓存中存在一个地址
的数据时,访问这个地址的时间更短,利用这个性质,攻击者可以得知一个地址
是否曾经被访问过。缓存计时攻击的常见形式有:

\begin{itemize}
\item Evict+Time: 攻击者清除一个缓存组,然后对一个算法的运行进行计时,
  检查它的运行时间是否受到影响
\item Prime+Probe: 受害者运行一段程序后,攻击者访问缓存某一组的每一路,
  观察访问时间是否有变化
\item Flush+Reload: 攻击者利用 x86 的 clflush 等指令清除一个共享内存地
  址对应的缓存行,在受害者运行一段程序后,攻击者重新装载该行对应的地址
  的数据,通过测量访问时间推断受害者是否访问了这个共享的地址
\end{itemize}

\section{Meltdown和Spectre攻击}

处理器在执行指令遇到异常,或者推测式执行了错误的指令后,会回卷错误执行
的指令,丢弃它们对体系结构状态的修改,这些被回卷的指令称为瞬时指令
(transient
instruction)。Meltdown\supercite{meltdown} 和
Spectre\supercite{spectre} 是最早发现的两个利用瞬时指令的攻击。此后发现
了更多的 Meltdown 和 Spectre 的变体。为了找出更多的攻击类型和分析它们的
防御方案,Claudio Canella 等人对这些攻击及其防御做了系统性的研
究\supercite{systematic},将所有瞬时执行攻击分为 Meltdown型攻击
和 Spectre 型攻击两类。

\subsection{Meltdown型攻击}

Meltdown 型攻击利用的是处理器异常产生的瞬时指令,这些指令使用了体系结构
层次上不可访问的数据,从而绕过硬件的安全策略,泄露体系结构层次上不可访
问的数据。

\subsubsection{Meltdown}

内存隔离是现代操作系统的核心安全功能之一。操作系统确保用户程序无法访问
其他程序的内存或内核的内存。这种隔离是现代计算环境的基石,使得系统上可
以同时运行多个应用程序,和多个用户的进程。

在现代处理器中,内核和用户进程之间的隔离通常由处理器的定义的权限位实现,
这一位定义了内核的页是否可以被访问。这一位只能在进入内核态时设置,并在
切换到用户态时清除。这个硬件特性使得操作系统可以将内核映射到每个进程的
地址空间,在终端处理等事件中,可以高效地从用户进程切换至内核。因此,在
操作系统的实现中,处理器从用户进程切换到内核时,不会改变内存映射。

Meltdown 是一种新型攻击,它使得任何用户进程可以简单地读取所在机器的整个
内核内存(包括映射在内核区域中的所有物理内存),从而完全破坏内存隔
离。Meltdown 不利用任何软件漏洞,适用于所有主流操作系统。Meltdown 利用
大多数现代处理器中侧信道信息,可以用于 2010 年以来的现代 Intel 处理器,
也可能可用于其他厂商的处理器。

侧通道攻击通常需要非常具体地了解目标应用程序,并且只用于泄露其中的秘密
信息,但 Meltdown 允许攻击者在可被攻击的处理器上,通过运行代码获得整个
内核地址空间的数据,包括任何映射在内核中的物理内存。Meltdown 的简单和
强大来自乱序执行的副作用。

乱序执行是现代处理器用于提高性能的重要特性,用于隐藏功能单元的延迟,例
如,读取内存的功能单元需要等待存储器中的数据到达。现代处理器在遇到长延
迟的执行时,不会停止执行,而是可以乱序操作,将后续的操作调度到空闲的功
能单元中。然而,这些操作通常有预期之外的副作用,例如,在顺序和乱序执行
中,时间差异都可能泄露信息。

从安全角度来看,一个观察特别重要:易受攻击的乱序处理器允许非特权态的进
程将数据从特权(内核或物理)地址载入临时的寄存器中。进一步,处理器可以
基于该寄存器的值进行计算,例如用这个寄存器的值访问数组。如果一条指令不
应该执行,通过简单地丢弃访问内存得到的结果,处理器可以确保程序执行的正
确性。因此,在体系结构层次,即处理器执行计算的抽象定义下,不会出现安全
问题。

但是,乱序执行中的内存访问会影响缓存,而缓存的状态又可以通过缓存侧通道
进行检测。因此,攻击者可以通过在乱序执行的指令流中,读取特权态的内存来,
来得到整个内核内存的数据,并通过微架构隐蔽通道传送出来,然后攻击者在隐
蔽信道的接收端,找出这个临时寄存器的值。因此,在微架构层次,即实际的
硬件实现中,存在可利用的安全性问题。

Meltdown 打破了处理器内存隔离功能提供的所有安全保障。这种攻击可以用于现
代台式机、笔记本电脑以及云服务器。 Meltdown 允许非特权进程读取映射在内
核地址空间中的数据,包括 Linux,Android 和 OS X 上的整个物理内存,以
及 Windows 上的大部分物理内存。这些内存可能包含其他进程的物理内存,以及
内核共享的容器沙箱(如 Docker,LXC)或半虚拟化模式下的 Xen 中,虚拟化管
理程序的内存,和其他虚拟化实例的内存。Meltdown 攻击的性能取决于处理器速
度、TLB 和高速缓存大小、DRAM 速度等,可以以 3.2KB/s 到 503KB/s 的速度
读取内核内存。因此,大量系统受到影响。

% background: address spaces
为了将不同的进程相互隔离,处理器支持虚拟地址空间,它将虚拟地址翻译为物
理地址。虚拟地址空间将内存划分为一系列的页,系统通过多级页表将虚拟页翻
译为物理页。页表是一个多级的结构,存放虚拟页到物理页的映射,同时,它还
保存了每个页的保护属性,用于处理器进行权限检查,例如可读、可写、可执行、
用户可读等。操作系统中每一个运行中的进程有一个对应的页表,页表所在的位
置存放在处理器中的一个特定寄存器中,在上下文切换时,操作系统会更新这个
寄存器,从而切换到处理器的进程可以使用这个进程对应的页表。利用这个机制,
每个进程的虚拟地址空间映射到不同的物理区域,每个进程只能使用自己地址空
间中的数据,从而达到进程间隔离的效果。

每个地址空间都可以分为用户地址空间和内核地址空间。正在运行的进程可以访
问用户地址空间,而内核地址空间只有进入内核态后可以访问,操作系统通过在
页表中设置内核地址空间的页为用户不可访问,来实现这个特性。内核地址空间
除了包含内核所要使用的数据外,通常还保存了整个物理内存的映射、文件缓存
等内容。

操作系统将内核地址空间映射至每个用户进程的地址空间中。处理器执行访存指
令时,在将虚拟地址翻译为物理地址的时候,检查地址对应的权限位,判断用户
是否可访问该地址。Meltdown攻击中,攻击者让处理器从用户不可访问的内核地
址装载数据至寄存器,由于所有内核地址都可以翻译为合法的物理地址,处理器
可以读取内核地址空间的数据,在产生异常前,攻击者构造的瞬时指令序列可以
将读取到的数据通过隐蔽信道发送给攻击者。

以下是一段 Meltdown 攻击的示例代码,通过它可以读取内核地址空间的数据:

\begin{minted}{nasm}
xor rax, rax
retry:
mov al, byte [rcx] ; 读取内核空间的数据
shl rax, 0xc
jz retry
mov rbx, qword [rbx + rax] ; 访问探测数组
\end{minted}

以上 X86 指令读取了以 rcx 为地址的内核空间的数据,在用户态下,这个读取
内核空间数据的指令会产生异常,但是在处理器产生异常之前,这条指令可以将
内核空间的数据读至寄存器,并且其后的指令也会执行,访问 rbx 指向的探测数
组。在处理器回卷了产生异常的指令和其后执行的指令后,高速缓存中仍然保留
了探测数组和内核数据相关的元素,从而攻击者可以通过扫描探测数组的每一
项,观察访问时间,以推测内核空间数据的值。

\subsubsection{Foreshadow}

% foreshadow introduction
由于现代广泛使用的操作系统和应用程序的大小可以轻松地达到数百万行代码,
并且单个漏洞通常会破坏所有安全保证,所以在安全上很难信任现有的操作系统
和应用程序。为了应对这些挑战,学术界和工业界开发了可信执行环境
(Trusted Execution Environment, TEE),其中包含一个处理器常规执行环境
之外的非分层保护模型,用于隔离应用程序,称为 enclave. TEE 利用只含有处
理器和微码的最小可信计算基础(Trusted Computing Base),来保证相互不信
任的 enclave 的保密性和完整性。 每个 enclave 的私有处理器和内存状态只可
以由其内部运行的代码访问,并且在任何特权级别(包括潜在的恶意操作系统和
虚拟机管理程序)上运行的所有其他 enclave 和软件都无法访问。除了强大的内
存隔离外,TEE 通常还提供一个证明(attestation)原语,从而可以本地或远程
地在运行时从密码学上验证特定的 enclave 已经加载到真正的(因而被认为是安
全的)TEE 处理器上。

随着 2013 年 Intel 软件防护扩展(Software Guard eXtention,
SGX)\supercite{sgx}的发布,硬件强制的 TEE 隔离和证明可以在现成的x86处
理器上使用。由于 Intel SGX 承诺的强大安全保障,越来越多的行业参与者将这
项技术应用于可受攻击者控制的机器上,需要安全执行的各种应用程序中。Open
Whisper Systems 依靠 SGX 在 Signal 网络中实现隐私友好的联系人发现功
能。\supercite{signal-sgx} 微软和 IBM 最近都宣布在其云基础架构中支
持 SGX。各种现成的蓝光播放器以及 4K Netflix 客户端使用 SGX 对高分辨率视
频流实施数字版权管理(DRM)。新兴的加密货币\supercite{mobilecoin}和的区
块链\supercite{sawtooth}技术更加依赖于 SGX 的正确性。

然而,当前的 SGX 实现并没有满足它的安全目标。Foreshadow 攻击利用现
代 Intel 处理器中的乱序执行机制,可以从处理器的缓存中泄露明文
的 enclave 数据。Foreshadow 攻击的核心是利用 Meltdown 攻击相同的处理器
漏洞,即处理器的访问控制逻辑允许攻击者在瞬态的乱序执行指令回滚之前,使
用未授权内存访问的结果。然而,Meltdown 攻击针对传统的分层保护域,
而 Foreshadow 考虑了一种非常不同的攻击模型,攻击者的目标不是从用户空间
读取内核内存,而是破坏最先进的地址空间内 enclave 保护域,它不在已经部署
的用于防御 Meltdown 的内核页表隔离技术的保护之内。Foreshadow 使用了一
种新的漏洞利用方法,并且基本的攻击完全可以由无特权的攻击者使用,而无需
用 root 权限访问受害者机器。对于有 root 权限的攻击者,还可以使用一组可
选的内核级优化技术,进一步降低 Foreshadow 攻击的噪声。

Foreshadow 对 Intel SGX 所追求的安全模型产生了深远的影响,在没有微码补
丁的情况下,当前的SGX处理器无法保证 enclave 的数据保密性,也无法证
明enclave 执行的完整性,包括英特尔自己的 enclave 架构。此外,尽管 SGX
希望内核级别的攻击者,但现有的 SGX 处理器甚至无法在没有特权的用户空间
攻击者面前保护 enclave 中的秘密数据。

所有先前已知的针对 SGX 的攻击都依赖于软件特定的侧信道泄露或软件漏
洞。 人们普遍认为,精心编写的 enclave 可以通过坚持良好的编码实践,例如
不使用依赖秘密数据的分支,来防止信息泄露。Intel 认为这些攻击都没有破
坏 SGX 的安全保证,防止侧信道攻击应该是 enclave 开发者的责任。 然
而,Foreshadow 否定了这一论点,因为它完全依赖于基本的 Intel x86 处理器
的行为,并且不利用任何软件漏洞,甚至不需要知道受害者 enclave 的源代码。

% foreshadow attack
\begin{figure}[htbp]
  \centering
  \includegraphics[width=0.8\textwidth]{addr-trans.eps}
  \caption{CPU 的地址翻译过程和 L1 终端错误的原理:图片的下半部分为文
    档描述的地址翻译过程,上半部分是微架构的行为。}
  \label{fig:addr-tran}
\end{figure}

在现代 Intel x86 处理器中,用一个虚拟内存地址访问内存时,处理器先在TLB
中查询对应的物理地址,如果 TLB 中没有这个地址对应的项,则会在页表中找到
虚拟地址对应的页表项,以获得对应的物理地址和访问权限信息。
如果在虚拟机环境中,则需要如图 \ref{fig:addr-tran} 所示,增加一个扩展
页表(Extended Page Table,EPT)的访问过程,将客户机的物理地址翻译为底
层物理机的物理地址。最后,启用了 Intel SGX 的处理器还会进一步检查地址
翻译的结果,确保这个地址翻译遵守硬件强制的 enclave 访问控制限制。如果
这三个独立的阶段报告一个访问违例,则处理器抛出一个页错误,控制流转向异
常处理代码,而对于 SGX,大多数的 enclave 内存违例会被处理器忽视,将内
存装载指令得到的值设为 abort page 的值 -1.

在体系结构层次上,以上的地址翻译过程在文档中有精确的描述。现代处理器为
了加快地址翻译和内存访问,使用了并行访问和额外的缓存结构。在 Meltdown类
型的攻击中,可以发现 Intel 的 CPU 将内存访问违例检查放到了指令提交的时
间,使得在页错误发生之前,未授权的内存内容仍然可以到达流水线中其后执行
的乱序执行的指令。Meltdown 攻击利用了这个时间窗口,在瞬时指令中,将只有
特权态能访问的内存编码至持久的微架构状态。

现代 Intel 处理器使用虚拟地址索引,物理地址标签的一级缓存。如
图\ref{fig:addr-tran} 所示,这种缓存索引方式使得地址翻译可以和一级缓存
的查询并行。在得到虚拟地址对应的一级缓存组后,处理器还需要知道是否有某
一路缓存含有需要的数据,因此处理器要将地址翻译得到的物理地址和缓存每一
路的物理地址标签对比,在某一个有效的缓存路存在正确的物理地址时,此时一
级缓存命中,数据返回至处理器的执行单元。

Foreshadow\supercite{foreshadow} 是一种可以读取 Intel SGX enclave 中秘
密数据的 Meltdown 型攻击。如果对 SGX 使用 Meltdown 攻击,攻击者读取未授
权的 enclave 内存,不会产生异常,而是读出 abort page 值 -1. 但是 abort
page 只在页权限检查通过后发生,攻击者可以将该页 present 位清除,即将该
页设为不存在,此时处理器便会产生异常,但由于一级缓存使用虚拟地址索引,
因此仍然可以从一级缓存读取该虚拟地址中的数据,从而瞬时指令可以泄露 SGX
enclave 中的数据。

通过将一个页设为不存在,绕过地址翻译,从一级缓存读取数据的攻击方
式,Intel 将其称为L1终端错误(L1 Terminal
Fault)\supercite{l1tf}。Foreshadow-NG\supercite{foreshadowNG} 利用相同
的原理,新增了Foreshadow-OS 和 Foreshadow-VMM 两种 Foreshadow 类型的攻
击,可以绕过操作系统和虚拟机的隔离。


% forshadow-OS
操作系统内核将虚拟内存页从内存交换至外部持久存储时,都需要清除页表项的
存在位。但是,根据处理器的体系结构规范\supercite{intel-spec},内核可以
根据需要,自由地使用标记为不存在的页表项中的剩余位。例如,操作系统可以
保持这些位不变,将它们归零,或者使用它们来存储用于把页从磁盘复制回内存
的元数据。因此,虽然非特权用户空间应用程序不能直接控制页表项,但是当页
表项取消映射相应的虚拟页时,操作系统在页表项中留下的元数据仍然可以指向
包含敏感数据的有效物理地址。在内核清除相应页表项中的存在位后,从用户空
间解引用未映射的页将导致终端错误。

Foreshadow-OS 利用了这种错误造成的瞬时执行的指令。虽然访问页表中标记为
不存在的页会触发终端错误存在,在页表项中的元数据表示在缓存中的物理地址
的情况下,处理器仍然将一级数据高速缓存中未授权数据传递到瞬时乱序执行中。
然后可以和其他瞬时执行攻击一样,将秘密数据从微架构瞬时执行域带入体系结
构状态中,例如,使用基于缓存的隐蔽通道。更糟糕的是,如果操作系统支持大
于 4KB 的页(例如,2MB 或 1GB),攻击者可以通过无意的映射访问最大页面大
小的内存范围。由于所有软件本质上共享相同的物理地址空间,因此元数据创建
的虚拟到物理映射可能指向属于操作系统内核,VMM 内存,SGX
enclave,或 SMM 内存的数据。在操作系统通过 munmap 系统调用释放内存时,
将页表项清零的常见情况下,攻击者可以访问存储在物理地址 0x00 的数据。

实验结果表明,在一个 i7-6820HQ CPU 上,Foreshadow-OS 通过利用瞬态执行,
可以从已清除存在位的页中读取一级缓存的数据。

% foreshadow-VMM

虽然上述 Foreshadow-OS 变体允许无特权的攻击者使用未经授权的物理内存位置
上的数据进行瞬时计算,但他们无法直接控制访问哪些物理地址。因此,
Foreshadow 攻击使用在可以直接控制客户机器物理地址和一级缓存标签比较的
不可信虚拟机时时,会变得更有破坏性。这种攻击称为 Foreshadow-VMM.

根据 Intel 处理器的架构规范\supercite{intel-spec},客户机物理地址经过基
于 EPT 的转换过程以找到底层主机物理内存地址。英特尔的分
析\supercite{l1tf}显示,终端错误发生时,虚拟地址到物理地址处于早期阶段,
在经过 EPT 转换之前,将转换出来的客户机物理地址传到一级缓存中进行标签比
较。因此,恶意虚拟机可以控制用于访问一级缓存的瞬时指令的物理地址。特别
的,不可信的恶意客户虚拟机可以在自己的客户页表中修改页表项,指向客户机
物理内存。该地址不会经过 EPT 转换,和一级缓存中的标签进行比较,就像它是
主机物理地址一样。

\begin{figure}[htbp]
  \centering
  \includegraphics[width=0.8\textwidth]{foreshadow-vmm.eps}
  \caption{Foreshadow VMM 的一种使用场景。同一物理核上的虚拟机共享一级
    缓存,攻击者可以操作其内存访问,读取受害者虚拟机在一级缓存的内容。}
  \label{fig:foreshadow-vmm}
\end{figure}

图 \ref{fig:foreshadow-vmm} 展示了一种情况,一个恶意的虚拟机可以利用瞬
时执行攻击窃取属于同一处理器核的另一个虚拟机中的数据。这种攻击并不局限
于超线程受害者,因为 Foreshadow-VMM 可以提取处理器物理核心一级数据高速
缓存中的任何秘密。


\subsubsection{LazyFP}

% introduction
LazyFP\supercite{lazyfp} 是一个 Meltdown 类型的攻击,它可以跨越进程和虚
拟机的边界,泄露浮点处理单元(FPU)寄存器的状态。这种攻击利用 Intel 处
理器处理设备不可用异常(\Fault{NM})的行为。这个异常用于在操作系统中实
现延迟 FPU 上下文切换的优化。在 LazyFP 攻击中,没有特权的本地执行的代码,
可以利用 \Fault{NM} 异常的瞬时指令,恢复受害者进程的 FPU 寄存器状态。
由于 AES-NI 的密钥等数据可能存在 FPU 寄存器中,这种攻击导致的数据泄露
对信息安全是个很大的威胁。

% background

x87 浮点单元(FPU)是 x86 的处理器的一个扩展,其最初目的是加速浮点数的
运算。它有自己的一组指令和寄存器。自 1989 年推出 Intel 486DX 以来,它是
每个 x86 微处理器不可或缺的一部分,而在此之前,它是一个可选的外部协处理
器。在上下文切换中,向内存保存 FPU 状态和恢复 FPU 的状态曾经是一个成本
很高的操作,因为内存速度慢并且大小有限。此外,那时 FPU 只在少数程序中被
使用。在 FPU 不被所有进程使用的情况下,在每个上下文切换时,切换 FPU 状
态会产生不必要的开销。为了能够减少这种开销,x86 处理器引入了一个控制寄
存器位 cr0.ts,允许操作系统打开和关闭FPU,当FPU关闭时,它会保持其状态,
但用户和内核代码都无法访问。

利用 cr0.ts 实现的优化称为延迟 FPU 上下文切换(lazy FPU context
switching)。核心思想是 FPU 寄存器状态仅在必要时进行上下文切换,并保留
在不使用 FPU 的进程中。这样,操作系统可以避免不必要的保存和恢复 FPU 上
下文的成本。

操作系统跟踪当前 FPU 寄存器状态所属的进程,此进程称为FPU所有者。FPU 可
以在启用和禁用状态,在 FPU 启用状态下,当前进程是 FPU 所有者,可以自由
地执行 FPU 指令。当操作系统切换到另一个进程时,FPU 被禁用。在进程尝试执
行 FPU 指令之前,它将保持禁用状态。由于 FPU 被禁用,使用浮点指令时,处
理器会生成 \Fault{NM} 异常。操作系统处理 \Fault{NM} 异常的方式取决于当
前进程是否为FPU 所有者,如果是,则 FPU 寄存器状态属于该进程,操作系统启
用FPU,该进程再次可以自由执行FPU指令。否则,则操作系统在启用 FPU 的同时,
将当前FPU 寄存器状态存储到 FPU 所有者进程的状态保存区域,并恢复当前进程
的FPU 寄存器状态,并将该进程设为 FPU 的所有者。

这个算法在不同操作系统中的实现可能不同,它们的共同点是,使用 FPU 的进程
切换到不使用 FPU 的进程时,操作系统不需要上下文切换 FPU 寄存器的状态。

虽然延迟 FPU 上下文切换仍然在现代的操作系统中广泛使用,但其基本假设通常
不再适用。从 Intel MMX 指令集扩展,到后续的 SSE,AVX 和 AVX-512,FPU 寄
存器状态已经扩展到更大的 SIMD 寄存器。SSE 指令集是 64 位 x86 处理器的必
须组成部分,并且在几乎所有程序和库中用于实现不同的任务,例如内存复制。

虽然更大的 FPU 寄存器状态使得避免 FPU 上下文切换更具吸引力,但在当前的
软件中,每个进程最终都会使用 FPU 寄存器并触发 \Fault{NM} 异常。因
此,Linux 内核已经默认将 FPU 寄存器作为普通上下文切换的一部分进行切换,
在正常操作中不会生成 \Fault{NM} 异常。

在使用 Intel 的硬件辅助虚拟化技术时,处理器在从客户机切换到管理程序时,
不会切换FPU寄存器状态。虚拟机管理程序负责上下文切换 FPU 寄存器的状态,
并且机制与非虚拟化操作系统的机制相同。因此,延迟 FPU 上下文切换也适用于
虚拟机管理程序。

在使用延迟 FPU 上下文切换的操作系统中,利用 LazyFP 攻击可以使没有特权的
攻击者获取同一处理器硬件线程中 FPU 寄存器的数据。以下简单的例子可以泄
露1比特的数据。

\begin{minted}{nasm}
movq rax, xmm0
and rax, 1
shl rax, 6
mov rax, dword [mem + rax]
\end{minted}

在以上代码片段中,由于进程中 FPU 寄存器被禁用,movq 指令产
生 \Fault{NM} 异常。操作系统会用对应用程序透明的方式处理该异常,恢复进
程的状态并继续执行。

而在处理器结束 movq 指令的执行并产生 \Fault{NM} 之前,已经执行了后续指
令,虽然最终这些指令引起的体系结构状态更改会被丢弃,但在缓存中的状态仍
然保留。这段代码使用了受害者进程的 FPU 寄存器和攻击者进程的通用寄存器
进行瞬时指令的执行,通过探测 mem 指向的数组的缓存状态,可以恢复 xmm0
最低位的值。

利用 Intel TSX 等技术处理异常,攻击者可以高效地泄露所有 FPU 寄存器的数
据。在 Intel Core i7-5600U 处理器中,可以以 3.3MB/s 的速度泄露一个 AVX
寄存器的数据。

\subsection{Spectre型攻击}

Spectre 型攻击利用处理器对控制流或数据流的预测,并进行推测式执行产生的
瞬时指令。Spectre 型攻击中,瞬时指令访问的是程序在体系结构层面能访问的
数据,可以绕过软件定义的安全策略,如边界检查等。

推测式执行的常见形式是控制流的推测式执行。控制流的推测式执行依赖于转移
预测技术,包含了分支的预测、间接转移目标地址的预测和函数返回地址的预测,
对应于 Spectre 攻击中 Spectre-PHT, Spectre-BTB, Spectre-RSB. 此外,处
理器预测 load 指令和程序序列之前访问地址未知的 store 指令地址不冲突,
推测式执行这样的 load 指令,它对应 Spectre-STL.

%%%% gtran: branch prediction

\Todo: 关于处理器执行转移指令的背景知识,是否需要?

\Fixme: 需要重新翻译的内容

在推测执行期间,处理器猜测分支指令的可能结果。更好的预测通过增加可成功
提交的推测性执行操作的数量来提高性能。

现代英特尔处理器的分支预测器,例如Haswell Xeon处理器,具有用于直接和间
接分支的多种预测机制。间接分支指令可以跳转到在运行时计算的任意目标地址。
例如,x86指令可以跳转到寄存器,存储器位置或堆栈中的地址,例如“jmp eax”,
“jmp [eax]”和“ret”。 ARM上也支持间接分支(例如,“MOV pc,r14”),MIPS
(例如,“jr \$ ra”),RISC-V(例如,“jalr x0,x1,0”)和其他处理器。与直
接分支相比,为了补偿额外的灵活性,使用至少两种不同的预测机制来优化间接
跳转和调用[35]。

英特尔[35]描述了处理器的预测
•以静态或单调方式进行“直接呼叫和跳转”,
•“间接呼叫和跳转”要么是单调的,要么是以不同的方式,这取决于最近的程序
行为,以及
•“条件分支”分支目标以及是否将采用分支。

因此,几个处理器组件用于预测分支的结果。分支目标缓冲区(BTB)保持从最
近执行的分支指令的地址到目标地址的映射[44]。即使在解码分支指令之前,处
理器也可以使用BTB来预测未来的代码地址。 Evtyushkin等。 [14]分析了英特
尔Haswell处理器的BTB,并得出结论,只有31个最低有效位的分支地址用于索引
BTB。

对于条件分支,记录目标地址对于预测分支的结果不是必需的,因为目的地通常
在指令中被编码,同时在运行时确定条件。为了改进预测,处理器维护分支结果
的记录,包括最近的直接和间接分支。 Bhattacharya等。 [9]分析了近期英特
尔处理器中分支历史预测的结构。

尽管返回指令是一种间接分支,但是在现代CPU中经常使用用于预测目标地址的
单独机制。返回堆栈缓冲区(RSB)维护最近使用的调用堆栈部分的副本[15]。
如果RSB中没有可用数据,则不同的处理器将停止执行或使用BTB作为回退[15]。

分支预测逻辑(例如,BTB和RSB)通常不在物理核心之间共享[19]。因此,处理
器仅从在同一核上执行的先前分支学习。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%% gtran: attack overview %%%%%%%%%%%%%%%%%%%%%%%5

\verb|TODO|: Spectre 攻击的 attack overview

\Fixme: 重新翻译此部分

Spectre 攻击诱使受害者推测性地执行在程序指令的严格序列化有序处理期间不
会发生的操作,并且通过隐蔽通道将受害者的机密信息泄露给对手。我们首先描
述利用条件分支错误预测的变体(第IV部分),然后利用对间接分支目标的错误
预测的变体(第V部分)。

在大多数情况下,攻击从设置阶段开始,其中攻击者执行操作以误导处理器,以
便稍后进行可利用的错误推测预测。此外,设置阶段通常包括有助于引发推测性
执行的步骤,例如操纵高速缓存状态以移除处理器将确定实际控制流所需的数据。
在设置阶段期间,攻击者还可以准备将​​用于提取受害者信息的隐蔽信道,例如,
通过执行刷新或驱逐部分Flush + Reload或Evict + Reload攻击。

在第二阶段期间,处理器推测性地执行将机密信息从受害者上下文传送到微架构
隐蔽信道的指令。这可以通过让攻击者请求受害者执行动作(例如,通过系统调
用,套接字或文件)来触发。在其他情况下,攻击者可以利用其自身代码的推测
(错误)执行来从同一进程获取敏感信息。例如,由解释器,即时编译器或“安
全”语言沙箱化的攻击代码可能希望读取它不应该访问的内存。虽然推测性执行
可能会通过广泛的隐蔽通道暴露敏感数据,但给出的示例会导致推测性执行首先
在攻击者选择的地址读取内存值,然后执行内存操作,以暴露出的方式修改缓存
状态值。

对于最后阶段,恢复敏感数据。对于使用Flush + Reload或Evict + Reload的
Spectre攻击,恢复过程包括对正在监视的缓存行中的内存地址的访问进行计时。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsubsection{Spectre-PHT}

Spectre-PHT 利用分支预测器,攻击者可以训练转移预测器,使得转移预测器执
行一个分支,该分支的指令序列可以泄露受害者地址空间或寄存器的信息。

Spectre v1 是最早提出的 Spectre 攻击,属于 Spectre-PHT 类型。它利用受
害者程序中的分支,一个例子如下:

\begin{figure}[htbp]
\begin{minted}[frame=single,linenos=true]{C}
if (x < array1_size)
    y = array2[array1[x] * 4096];
\end{minted}
\caption{Spectre v1 受害者代码}
\label{lst:spectre_v1}
\end{figure}

%%%%%%%%%%%%%%%%%%%%%%% gtran: spectre v1 %%%%%%%%%%%%%%%%%%%%%%%%%%%

\verb|TODO|: Spectre 论文中 Spectre v1 的内容

\verb|TODO|: 解释 Spectre 攻击中这段代码的运行方式,关于在 Javascript 和 eBPF 下的攻击

\Fixme: 重新翻译

代码片段以对x的边界检查开始,这对于安全性是必不可少的。特别是,此检查
可防止处理器读取array1外部的敏感内存。否则,越界输入x可能触发异常或者
可能导致处理器通过提供x =(要读取的秘密字节的地址)来访问敏感存储器 -
(array1的基址)。

\begin{figure}[htbp]
  \centering
  \includegraphics[width=0.8\textwidth]{spectre_v1.eps}
  \caption{在得出边界检查的正确结果之前,分支预测器使程序从最可能的分
    支目标继续运行,如果预测结果正确,则可以得到性能提升。但是,如果边
    界检查预测错误,攻击者在一些情形可以泄露秘密数据。}
  \label{fig:spectre_v1}
\end{figure}

图1结合推测执行说明了边界检查的四种情况。在已知边界检查的结果之前,CPU
通过预测比较的最可能结果来推测性地执行该条件之后的代码。有许多原因可能
导致边界检查的结果不能立即被知道,例如,在边界检查之前或期间的高速缓存
未命中,边界检查所需的执行单元的拥塞,复杂的算术依赖性或嵌套的推测执行。
然而,如图所示,在这些情况下对条件的正确预测导致更快的整体执行。

不幸的是,在推测执行期间,边界检查的条件分支可能遵循不正确的路径。在此
示例中,假设攻击者导致代码运行,使得:

\begin{itemize}
\item 选择一个恶意越界的 x 的值,使得 \verb|array1[x]| 指向受害者内存中的某个
  秘密字节 \verb|k|
\item \verb|array1_size| 和 \verb|array2| 不在缓存中,但 \verb|k| 在缓存中
\item 此前的操作中接收到的 \verb|x| 值均有效,使得分支预测器预测 if 为
  真
\end{itemize}

该高速缓存配置可以自然发生或者可以由对手创建,例如,通过导致驱逐
\verb|array1_size| 和 \verb|array2|,然后让内核在合法操作中使用秘密密钥。

当上面编译的代码运行时,处理器首先将x的恶意值与array1\_size进行比较。读
取array1\_size导致高速缓存未命中,并且处理器面临相当大的延迟,直到其值
可从DRAM获得。特别是如果分支条件或分支之前某处的指令等待未缓存的参数,
则可能需要一些时间才能确定分支结果。与此同时,分支预测器假定if为真。因
此,推测执行逻辑将x添加到array1的基地址,并从存储器子系统请求结果地址
处的数据。该读取是高速缓存命中,并快速返回秘密字节k的值。推测执行逻辑
然后使用k来计算array2 [k * 4096]的地址。然后它发送一个从内存中读取该地
址的请求(导致缓存未命中)。虽然从array2读取已经在飞行中,但最终可以确
定分支结果。处理器意识到它的推测执行是错误的并且重新调整其寄存器状态。
但是,来自array2的推测性读取以特定于地址的方式影响高速缓存状态,其中地
址取决于k。

为了完成攻击,攻击者测量array2中的哪个位置被带入缓存,例如,通过Flush
+ Reload或Prim + Probe。这揭示了k的值,因为受害者的推测执行缓存了
array2 [k * 4096]。或者,对手也可以使用Evict + Time,即,使用入境值x'
立即再次调用目标函数,并测量第二次调用所花费的时间。如果array1 [x']等
于k,那么在array2中访问的位置在缓存中,并且操作趋于更快。

许多不同的情况可能导致使用此变体的可利用泄漏。例如,代替执行边界检查,
错误预测的条件分支可以检查先前计算的安全结果或对象类型。类似地,推测性
地执行的代码可以采用其他形式,例如将比较结果泄漏到固定的存储器位置,或
者可以分布在更大数量的指令上。上述高速缓存状态也比可能需要的更严格。例
如,在某些情况下,即使缓存了array1\_size,攻击仍然有效,例如,如果在推
测执行期间应用分支预测结果,即使比较中涉及的值是已知的。根据处理器,也
可以在各种情况下启动推测执行。其他变体在第VI节中讨论。

我们在多个x86处理器架构上进行了实验,包括Intel Ivy Bridge(i7-3630QM),
Intel Haswell(i7-4650U),Intel Broadwell(i7-5650U),Intel Skylake
(Google云端未指定Xeon,i5-6200U,i7- 6600U,i7-6700K),Intel Kaby
Lake(i7-7660U)和AMD Ryzen。在所有这些CPU上都观察到了Spectre漏洞。在
32位和64位模式以及Linux和Windows上都观察到类似的结果。一些基于ARM架构
的处理器也支持推测性执行[7],以及我们对Qualcomm Snapdragon 835 SoC(带
有Qualcomm Kyro 280 CPU)和三星Exynos 7420 Octa SoC(带Cortex-A57和
Cortex-A53)的初始测试CPU)确认这些ARM处理器受到影响。我们还观察到推测
性执行可以远远超出指令指针。在Haswell i7-4650U上,附录C中的代码(参见
第IV-B节)可以在'if'语句和访问array1 / array2的行之间的源代码中插入多
达188条简单指令,这些指令就在下面适合该处理器重排序缓冲区的192个微操作
(参见第II-B节)。

我们在JavaScript中开发了一个概念验证,并在Google Chrome版本62.0.3202中
对其进行了测试,该版本允许网站从其运行的进程中读取私有内存。代码如清单
2所示。

在分支预测器错误引用过程中,索引(通过位操作)设置为范围内值。在最后一
次迭代中,index被设置为simpleByteArray的越界地址。我们使用变量
localJunk来确保不优化操作。根据ECMAScript 5.1 Section 11.10 [13],“|
0”操作将值转换为32位整数,作为JavaScript解释器的优化提示。与其他优化的
JavaScript引擎一样,V8执行即时编译以将JavaScript转换为机器语言。虚拟操
作放在清单2中的代码中,以使simpleByteArray.length存储在本地内存中,以
便在攻击期间将其从缓存中删除。有关D8的结果反汇编输出,请参见清单3。

由于无法从JavaScript访问clflush指令,我们使用缓存逐出[27,51],即,我们
以某种方式访问​​其他存储器位置,以便之后逐出目标存储器位置。泄漏的结果通
过probeTable [n * 4096]的缓存状态传递,n∈0..255,因此攻击者必须驱逐这
256个缓存行。长度参数(JavaScript代码中的simpleByteArray.length和反汇
编中的[ebp-0xe0])也需要逐出。 JavaScript不提供对rdtscp指令的访问,并
且Chrome故意降低其高分辨率计时器的准确性以使用performance.now()[62]
来阻止定时攻击。但是,HTML5的Web Workers功能使创建一个单独的线程变得简
单,该线程反复递减共享内存位置中的值[24,60]。这种方法产生了一个提供足
够分辨率的高分辨率计时器。

作为利用条件分支的第三个例子,我们开发了一个可靠的概念验证,它通过滥用
eBPF(扩展BPF)接口从未修改的Linux内核泄漏内核内存,而没有针对Specter
的补丁。 eBPF是一个基于伯克利数据包过滤器(BPF)[49]的Linux内核接口,
可用于各种目的,包括根据数据包内容过滤数据包。 eBPF允许非特权用户在内
核的上下文中触发解释或JIT编译以及随后执行用户提供的,内核验证的eBPF字
节码。攻击的基本概念类似于针对JavaScript的攻击概念。

在此次攻击中,我们仅将eBPF代码用于推测性执行的代码。我们在用户空间中使
用本机代码来获取隐藏的信道信息。这与上面的JavaScript示例不同,后者的两
个函数都是用脚本语言实现的。为了推测性地访问用户空间内存中依赖于机密的
位置,我们对内核内存中的数组执行推测性的越界内存访问,其索引足够大,以
便访问用户空间内存。概念验证假定目标处理器不支持超级用户模式访问保护
(SMAP)。但是,没有这种假设的攻击也是可能的。它在Intel Xeon Haswell
E5-1650 v3上进行了测试,它在默认解释模式和eBPF的非默认JIT编译模式下都
可以使用。在高度优化的实现中,我们能够在此设置中泄漏高达2000B / s。它
还在AMD PRO A8-9600 R7处理器上进行了测试,它只能在非默认的JIT编译模式
下工作。我们将调查原因留给未来的工作。

eBPF子系统管理存储在内核内存中的数据结构。用户可以请求创建这些数据结构,
然后可以从eBPF字节码访问这些数据结构。为了强制执行这些操作的内存安全性,
内核存储与每个此类数据结构相关联的一些元数据,并对此元数据执行检查。特
别地,元数据包括数据结构的大小(在创建数据结构时设置一次并用于防止越界
访问)以及加载到内核中的eBPF程序的引用数量。引用计数跟踪引用数据结构的
多少eBPF程序正在运行,确保不释放属于数据结构的内存
加载的eBPF程序引用它。

我们通过滥用错误共享来增加边界检查的延迟与eBPF管理的阵列的长度。内核将
数组长度和引用计数存储在同一缓存行中,允许攻击者将包含数组长度的缓存行
移动到处于Modified状态的另一个物理CPU核心(参见[16,53])。这是通过加载
和丢弃引用另一个物理内核上的eBPF阵列的eBPF程序来完成的,这会导致内核在
另一个物理内核上递增和递减阵列的引用计数器。这种攻击在Haswell CPU上实
现了大约5000B / s的泄漏率。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\verb|TODO|: Spectre v1.1的内容,需要更详细地解释攻击原理

推测式缓冲区溢出(Speculative Buffer Overflow)
\supercite{spec-buffer-overflow} 是 Spectre-PHT 的另一种形式。处理器存
在一个存储缓冲区(store buffer),往存储系统写入的数据在指令提交前将写
入数据的地址和值存放在这个缓冲区中,后续的指令要使用这个地址的值时,可
以将缓冲区中的数据转发给需要的指令。推测式缓冲区溢出利用了这个特性,例
如以下程序:

\begin{minted}{C}
if (x < len)
    a[x] = z;
\end{minted}

攻击者给出一个超过数组 \verb|a| 大小的 \verb|x| 时,在推测式执行时,会
将 \verb|a[x]| 的地址和攻击者输入的值 \verb|z| 写入至存储缓冲区。如果
\verb|a[x]| 的地址是一个函数在栈中存放的返回地址,这段程序之后有返回指
令,返回指令就会从存储缓冲区读取这个函数的返回地址,并从这个地址开始执
行指令,从而攻击者可以使程序在推测式执行时执行以 \verb|z| 为地址开始的
指令流。通过构造输入 \verb|x| 和 \verb|z|,攻击者可以使处理器在推测式
执行中执行攻击者指定的代码,这些代码可能会将程序中的秘密数据泄露在微架
构状态中。

\subsubsection{Spectre-BTB}

Spectre v2 利用间接转移的推测式执行,用于预测间接转移的主要部件是 BTB,
因此在分类上称为 Spectre-BTB.

在 Spectre v2 中,攻击者可以对间接转移进行投毒,从而可以利用由此产生的
转移预测错误,从另一个上下文(如另一进程)中读取任意内存。如果由于缓存
缺失等原因,需要较长延迟得到间接转移的目标地址,则处理器从此前预测的目
标地址处进行推测式执行。

\begin{figure}[htbp]
  \centering
  \includegraphics[width=0.8\textwidth]{spectre_v2.eps}
  \caption{转移预测器在攻击者控制的上下文 A 中训练。在上下文 B 中,转移
    预测器根据在上下文 A 中的训练结果进行预测,导致处理器跳转至攻击者选
    择的目标地址处进行推测式执行,该目标地址处存放着受害者地址空间中
    的 Spectre组件。}
  \label{fig:spectre_v2}
\end{figure}

攻击者可以用恶意的目标地址训练转移预测器,从而处理器转移到攻击者选择的
地址进行推测式执行。在图\ref{fig:spectre_v2}中,转移预测器可以在一个上
下文中训练,在另一个上下文中进行预测。攻击者可以引导受害者推测式执行在
正确的程序执行中永远不会执行的位置。由于推测性执行带来了可测量的副作
用,这种攻击对于攻击者来说及其强大,即使在没有可利用的条件分支错误预测
的情况下,也可以用它泄露受害者的内存。

举一个简单的攻击例子,攻击者试图读取受害者的内存,当发生间接转移时,攻
击者可以控制两个寄存器。这在现实的二进制程序中很常见,因为操作从外部接
收数据的函数通常会进行函数调用,此时寄存器包含攻击者控制的值。

攻击者还需要找到一个 Spectre 组件,它是一个用于在推测式执行中,将受害者
的敏感信息转移到隐蔽通道中的代码片段。在这个例子中,一个有效的组件可以
由两个指令组成。一个将攻击者控制的 R1 指向的内存加到攻击者控制的寄存
器R2 上,接下来一个指令用 R2 访问内存。在这种情况下,Spectre 组件可以让
攻击者通过 R1 控制泄露的地址,以及攻击者通过 R2 控制第二条指令读取泄露
数据对应的地址。Spectre 组件需要在受害者可执行的内存中,由于大多数进程
在内存中映射了很大的共享库,攻击者有足够多的空间找到这样的组件,而不需
要搜索受害者程序的代码。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% gtran %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\verb|TODO|: Spectre 的论文中关于 Spectre v2 一节的剩余内容,一直到实验结果部
分

\Fixme: 重新翻译以下内容

许多其他攻击是可能的,这取决于对手所知道或控制的状态,对手所寻求的信息
所在的位置(例如,寄存器,堆栈,内存等),对手控制推测执行的能力,指令
序列可用于形成小工具,以及哪些渠道可能会泄漏来自投机操作的信息。例如,
如果攻击者可以简单地在将来自寄存器中指定的地址的存储器带入高速缓存的指
令中诱导推测执行,则在寄存器中返回秘密值的加密函数可能变得可利用。同样,
尽管上面的示例假设攻击者控制两个寄存器,但攻击者控制单个寄存器,堆栈上
的值或内存值对于某些小工具来说已足够。

在许多方面,利用类似于面向返回的编程(ROP),除了正确编写的软件易受攻
击,小工具的持续时间有限但不需要干净地终止(因为CPU最终会识别推测错误)
和小工具必须通过旁道而不是明确地渗透数据。仍然,推测执行可以执行复杂的
指令序列,包括从堆栈读取,执行算术,分支(包括多次)和读取存储器。

在x86处理器上模糊分支预测器。

攻击者从其自己的上下文中执行分支预测器的错误操作,以欺骗处理器在运行受
害者代码时推测性地执行小工具。我们的攻击过程模仿受害者的分支模式导致分
支被误导。

请注意,历史错误要求因CPU而异。例如,在Haswell i7-4650U上,使用了大约
29个先前目标地址的低20位,尽管观察到在这些地址上进行了一些进一步的散列。
在AMD Ryzen上,仅使用大约前9个分支的低12位。附录A中提供了用于更新Intel
Xeon Haswell E5-1650 v3上的分支历史缓冲区的反向工程伪代码。

此外,我们在攻击者的同一个虚拟地址处设置了一个跳跃,就像在受害者进程中
一样。注意,这可能不是必需的,例如,如果CPU仅基于跳转地址的低位索引预
测。在设计分支预测器时,我们只需要模拟虚拟地址;物理地址,时间和进程ID
似乎并不重要。由于分支预测不受其他内核上的操作的影响(参见第II-C节),
因此必须在同一CPU内核上进行任何错误训练。

我们还观察到分支预测器从非法目的地的跳跃中学习。虽然在攻击者的进程中触
发了异常,但这可以很容易地捕获,例如,使用Linux上的信号处理程序或
Windows上的结构化异常处理。与前一种情况一样,分支预测器然后将进行预测,
将其他进程发送到相同的目标地址,但是在受害者的虚拟地址空间(即,小工具
所在的地址空间)中。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


\subsubsection{Spectre-RSB}

返回栈(RSB)用于预测程序函数调用的返回地址。如果 RSB 中的返回地址和实
际返回地址不同,则会产生错误的推测式执行,
SpectreRSB\supercite{spectre-returns}\supercite{ret2spec} 利用了这种错
误的推测式执行进行攻击。

Spectre-RSB 的利用方式包括使 RSB 溢出,及污染 RSB. RSB 的大小为普通程
序函数调用深度,调用深度超过 RSB 的大小时,会造成RSB 溢出,覆盖其中最
老的条目,在函数返回时,会发生 RSB 下溢出。而有的处理器在 RSB 为空时,
使用 BTB 进行转移预测,攻击者可以用 Spectre-BTB 的攻击方式进行攻击。污
染 RSB 的方法包括在处理器的不同上下文中使用 RSB,推测式污染 RSB 等。

\subsubsection{Spectre-STL}

Spectre v4 利用的是 load 指令的推测式执行。处理器执行 load 指令时,如
果此前有地址未知的 store 指令,会认为这个 load 指令和这些地址未知的
store 指令地址不同,并推测式执行这个 load 指令,将其地址中的值装入目的
寄存器。如果在计算出 store 的地址后,发现和已执行 load 访问了相同数据,
则处理器需要重新执行这个 load 和之后的指令。在推测式执行的过程中,瞬时
指令可以泄露这个地址中的旧值。

\section{Meltdown 和 Spectre 的其他形式}

在研究 Meltdown 和 Spectre 攻击的过程中,研究者还发现了一起其他的攻击
形式,它们基于已有的 Meltdown 和 Spectre 攻击,使用不同的利用方式。

\subsection{MeltdownPrime 和 SpectrePrime}

MeltdownPrime 和 SpectrePrime \supercite{meltdownprime} 是一种使用
Prime+Probe 方式进行 Meltdown 和 Spectre 攻击的形式。通过利用缓存一致
性协议的缓存行失效机制,可以达到和 Flush+Reload 方式的同等精度。

\subsection{NetSpectre}

%%%%%%%%%%%%%%%%%% gtran %%%%%%%%%%%%%%%%%%%%%%%%%%%

\verb|TODO|: NetSpectre 的 introduction

\Fixme: 重新翻译此内容

迄今为止,在JavaScript [48]和本机代码[15,48,58,75]中已经证明了幽灵攻击,
但是任何允许足够精确的定时测量和某种形式的代码执行的环境都可能实现这些
攻击。对英特尔SGX飞地的攻击表明,飞地也容易受到幽灵攻击[15]。但是,有
数十亿的设备从不运行任何攻击者控制的代码,即没有JavaScript,没有本机代
码,并且目标系统上没有其他形式的代码执行。到目前为止,这些系统被认为可
以安全地抵御此类攻击。事实上,供应商确信这些系统仍然是安全的,并建议不
要对这些设备采取任何措施[42]。

在本文中,我们提出NetSpectre,一种基于Spectre变体1的新攻击,不需要攻击
者控制的代码
设备,从而影响数十亿设备。与本地Spectre攻击类似,我们的远程攻击要求目
标代码中存在Spectre小工具。我们展示了在暴露的网络接口或API中包含所需
Spectre小工具的系统可能受到我们的通用远程Specter攻击的攻击,允许通过网
络读取任意内存。攻击者只向受害者发送一系列精心设计的请求,并测量从受害
者的记忆中泄漏秘密值的响应时间。

我们表明,内存访问延迟通常可以反映在网络请求的延迟中。因此,我们证明了
攻击者可以通过测量和平均大量测量来远程区分特定高速缓存行上的高速缓存命
中和未命中。基于此,我们实施了第一个访问驱动的远程缓存攻击,一个名为
Thrash + Reload的Evict + Reload的远程变体。我们的远程Thrash + Reload攻
击是先前对加密算法的远程缓存定时攻击的重大飞跃[1,5,11,16,46,82]。我们
推动这种技术将现有的Spectre攻击改造为基于网络的场景。此NetSpectre变体
每小时可从易受攻击的目标系统泄漏15位。

通过利用基于AVX2指令执行时间的先前未知的侧通道,我们还演示了第一个完全
不依赖于缓存隐藏通道的Spectre攻击。我们基于AVX的隐蔽通道实现了每秒125
字节的本机代码性能,错误率为0.58%。通过在我们的NetSpectre攻击中使用此
隐蔽通道而不是缓存隐藏通道,我们可以实现更高的性能。由于不再需要高速缓
存驱逐,因此我们将局域网中目标系统的泄漏速度提高到每小时60位。在Google
云中,我们每小时可以从另一台独立虚拟机泄漏大约3位。

我们证明使用先前忽略的小工具可以在远程攻击中破坏地址空间布局随机化。
地址空间布局随机化(ASLR)是当今部署在大多数系统上的防御机制,几乎所有
地址都是随机的。具有本地代码执行功能的攻击者可以轻松绕过ASLR,因为ASLR
主要用于防御远程攻击
但不是本地攻击。因此,到目前为止,Spectre攻击的许多较弱的小工具都被忽
略了,因为它们不允许泄漏实际数据,而只是泄漏地址信息。但是,转向远程攻
击情形,这些较弱的小工具变得非常强大。

幽灵小工具可能比以前的工作更加通用。这不仅体现在我们在远程ASLR中断时使
用的较弱的小工具,而且我们提出的价值阈值技术更是如此。值阈值不使用典型
的位选择和内存参考机制,如之前的Spectre攻击所示。相反,价值阈值通过使
用类似于二元搜索的分而治之的方法直接利用比较中的信息泄漏。

NetSpectre标志着从本地攻击到远程攻击的范式转变。这显着扩大了范围并增加
了受影响设备的数量。特别是,Spectre攻击还必须被视为对不运行任何不受信
任的攻击者控制代码的设备的安全性的威胁。这表明反措施也必须适用于以前认
为安全的这些设备。我们提出了Retpolines [77]的新替代品,它具有更清晰的
结构。关于幽灵攻击和幽灵缓解的未来研究面临着我们概述的一系列挑战。这些
挑战表明,目前的防御措施只能是临时解决方案,因为它们只能解决症状而不解
决问题的根本原因。

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 

%%%%%%%%%%%%%%%%% gtran %%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\verb|TODO|: NetSpectre 的 attack overview

\Fixme: 重新翻译

在知道实际条件之前,CPU预测条件的最可能结果,然后继续相应的代码路径。
有几个原因导致在评估时不知道条件的结果,例如条件的部分缓存未命中,尚未
满足的复杂依赖性,或者所需执行单元中的瓶颈。通过隐藏这些延迟,如果条件
被正确预测,推测执行会导致更快的整体执行。错误预测条件的中间结果根本不
会提交到架构状态,并且有效性能类似于处理器永远不会执行任何操作然而,在
推测性执行期间发生的微体系结构状态的任何修改(例如高速缓存状态)都不会
被还原。

由于我们的NetSpectre攻击是通过网络安装的,因此受害设备需要攻击者可以访
问的网络接口。攻击者必须能够向受害者发送大量网络数据包。但是,这些不一
定必须在其中
很短的时间。此外,我们攻击中的数据包内容不需要受攻击者控制。

与本地幽灵攻击相比,我们的NetSpectre攻击并没有分为两个阶段。相反,攻击
者不断执行操作以使处理器出错,这将使其经常遇到可利用的错误推测执行。
NetSpectre不会跨越进程边界,而是通过将有效和无效值交替地传递给暴露的接
口(例如,有效和无效的网络数据包)来就地进行训练。对于我们的NetSpectre
攻击,攻击者需要两个Spectre小工具,如果收到网络数据包,则会执行这些小
工具:泄漏小工具和传输小工具。泄漏小工具在攻击者控制的索引处访问位流,
并根据所访问位的状态改变一些微架构状态。传输小工具执行任意操作,其中运
行时取决于泄漏小工具修改的微架构状态。在大量噪声中,攻击者可以观察到网
络数据包响应时间的这种时序差异。 Spectre小工具常见于现代网络驱动程序,
网络堆栈和网络服务实现中。

为了说明我们的NetSpectre攻击的工作原理,我们在一个适应的场景中考虑一个
类似于原始Specter变体1示例[48]的基本示例:清单1中的代码是在收到网络数
据包时执行的函数的一部分。我们假设x是攻击者控制的,例如,包头中的字段
或某些API的索引。此代码构成我们的泄漏小工具。

\begin{minted}{C}
if (x < bitstream_length)
  if (bitstream[x])
    flag = true;
\end{minted}

  代码片段以x的绑定检查开始,这是开发安全软件时的最佳实践。特别是,该
  检查防止处理器读取比特流之外的敏感存储器。否则,越界输入x可能触发异
  常或者可能通过提供x =(要读取的秘密位的地址) - (比特流的基地址)来
  使处理器访问敏感存储器。

  为了利用远程攻击中推测性执行期间的微体系结构状态变化,攻击者必须适应
  原始的幽灵攻击。攻击者可以远程诱导推测性执行,如下所示:

  (1)攻击者发送多个网络数据包,使得攻击者选择的x值总是在边界内。这会
  训练分支预测器,增加分支预测器预测比较结果为真的机会。
  (2)攻击者发送一个数据包,其中x超出界限,使得比特流[x]是目标存储器
  中的一个秘密位。
  (3)根据条件的最近分支结果,分支预测器假定边界检查为真,并且推测性
  地执行存储器访问。

  虽然在解决了条件的正确结果后未提交架构状态的更改,但不会还原微架构状
  态的更改。在清单1的代码中,这意味着虽然flag的值没有改变,但是flag的
  缓存状态确实发生了变化。仅当设置了比特流[x]处的秘密比特时,才缓存标
  志。

  传输小工具更简单,因为它只需要在任意操作中使用标志。因此,小工具的执
  行时间将取决于标志的高速缓存状态。在最简单的情况下,传输小工具只返回
  flag的值,该值由泄漏小工具设置。由于标志的架构状态(即其值)对于越界
  x不会改变,因此它不会泄露秘密信息。但是,发送小工具的响应时间取决于
  标志的微体系结构状态(即,是否被高速缓存),这确实泄漏了一个秘密位。

  为了完成攻击,攻击者测量每个秘密位泄漏的响应时间。由于响应时间的差异
  在纳秒范围内,攻击者需要对大量测量进行平均以获得具有可接受置信度的秘
  密值。实际上,我们的实验表明,在进行大量测量时,微结构状态的差异变得
  明显。因此,攻击者可以首先测量两个角落情况(即,缓存和未缓存)和之后,
  以提取真实秘密位,执行尽可能多的测量以区分具有足够置信度的情况,例如,
  使用阈值或贝叶斯分类器。

  我们将这两个小工具,即泄漏小工具和传输小工具称为NetSpectre小工具。运
  行NetSpectre小工具可能需要发送多个数据包。此外,泄漏小工具和传输小工
  具可以通过不同的独立接口来访问,即,攻击者必须可以访问这两个接口。

\begin{figure}[htbp]
  \centering
  \includegraphics[width=0.8\textwidth]{netspectre.eps}
  \caption{NetSpectre 的泄露组件和传输组件}
  \label{fig:spectre_v2}
\end{figure}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


NetSpectre 可以在局域网,或者 Google cloud 等云平台中使用。利用
Evict+Reload 缓存信道,每小时可以泄露 15 比特。利用基于 AVX 的隐蔽信道,
可以每小时泄露 60 比特。

\subsection{SgxPectre}

SgxPectre \supercite{sgxpectre} 将 Spectre 攻击用于泄露 Intel SGX 环境
中的数据。通过在 SGX enclave 之外污染 BTB,可以改变 SGX enclave 中的控
制流,进行 Spectre-BTB 攻击。

% vim:ts=4:sw=4