作者jk21234 (BL2400PT真不错)
看板PC_Shopping
标题Re: [情报] Intel严重漏洞 OS更新将会降低效能
时间Sat Jan 6 00:20:55 2018
为什麽cache预料之外的hit会导致data外流....
其实表面来说 资料没有被读出来 但是是被穷举的方式猜出来的
基本原理
0. int64 a = rdtsc()
RDTSC = Read the Time Stamp Counter,
这个数字从开机的时候就从0开始增加,一个cycle + 1.
这个指令不用进入高权限模式就可以执行
Pentium 75开始就有,在1995之後大量被使用
来测试效能 或者是作速度控制.
导致为了相容性不容易把它拔掉或者禁止低权限模式使用
有些范例会用进阶的rdtscp(),这个是修正版本
需要SSE2,但是跟多核心cpu相容...RDTSC在多核心cpu的值
不一样,本用途则差异不大
int64 a = rdtsc()
b = load_mem(ADR_A)
a = rdtsc() - a
这时候a会相近於这次load_mem所花掉的cycle数,
有一些误差 但是通常在10 cycle以下
如果我做两次 一次得到的a是> 200 , 一次是 < 20,
对cpu有点了解的就知道,cpu有一种叫做cache的机制
让读取有些时候可以加快不用那麽慢
所以很直觉的, >200 应该表示cache miss , 原本不在cache中,
< 20 , 上次应该就在cache中
这个後面会应用到
<======想按左键吗??
1. 假设已知CPU的最後一层Cache 有10MB, 而且为12-way,
如果我有一个阵列U[10MB].考虑最简单的情况
我连续读取这10MB之後那一瞬间,是不是会把cache中原本的资料几乎
全部洗出来,cache中几乎全部是我这10MB的资料.
是的 这是基本假设
然後我们进阶一点,cache被U[10MB]塞满之後 我再load_mem(A),
这时候因为cache没有他的资料,一定是cache miss,然後放弃掉U[10MB]中的
某区块不在cache中,下次就是这个区块的记忆体万一又要读取到 就会miss
(中间省略)最後针对一个Address A,我都可以在U中找到32Byte*12
总共384Byte的位址 只要这群资料用12个load_mem()读入,就会
保证Address A的资料被挤出Cache
Q1:所以要先知道cpu cache的大小跟规格???
A:不用 用前面的方法本身就可以探索出cpu cache的最大值
跟way-associative的数值,其实就是拿各种size的阵列U
读取跟分割读取,可以求到的数值
2.
a = rdtsc()
b = load_mem(SYSTEM_A)
a = rdtsc() - a
会发生甚麽事情?如果SYSTEM_A是一个猜的Address,位在保护区段且不可读取
其实正常就是产生General Protection Fault,但可以Program自己接手回来
这个Exception
正常来说, B不会被更新, 但关键在第二次的rdtsc()甚麽时候执行
Out of order 有可能
a. load_mem之前
b. load_mem之後,exception之前
c. exception之後
第一种情况会得到一个特小个位数的值 也可以用mem_barrier()
或者mem_fence() (这两种指令是规定指令与mem_load要排队)
隔离开 第一种情况基本上就不会发生
第二种情况 惊异的是它很接近一般的mem_load,有时候可以看到
> 200t, 有时候看到 < 20t,明明SYSTEM_A就不给读取...
第三种就是rdtsc会超长,1000cycle内不太可能,或者.多核心之下不一定正常
可以当杂讯值排除
不是用这个方法 但是继续进化的话...
3.设定一个阵列X,可以是256 Byte,或者适当的倍数
然後我同样有个U[10MB]的阵列
a = rdtsc()
b = load_mem(SYSTEM_A)
c = load_mem(&X + b)
mem_fense()
a = rdtsc() - a
第一次做无效的SYSTEM_A的load, B不会得到结果
但是,我这端不知道B的值 可是CPU知道X阵列的第B个元素
加起来是多少,他去载入这个位置了.....会在C拿到吗
不会 第一次load_mem无效,第二次load_mem一样无效
至於exception的问题同前,但是多跑几次在这组行为中看到cache miss
与cache hit的时间差异
然後我找个样本
a = rdtsc()
b = load_mem(DUMMY)
c = load_mem(&X + 0)
mem_fense()
a = rdtsc() - a
找出U[10MB]之中,对第二次&X + 0
具有cache互斥性的384 Byte资料为一组
抽出来 跟
a = rdtsc()
b = load_mem(SYSTEM_A)
c = load_mem(&X + B)
mem_fense()
a = rdtsc() - a
一起玩
如果发现&X + B的载入行为,Cache Miss的时间
和&X + 0的对照组相同
那麽, B的内容就是0
如果比照起来不相似&X + 0与它的384 byte伙伴的相处关系
那就要再找&X + 1,这时候是另外384 byte快乐伙伴
来比较.....最多比较256次来确定一个Byte
实际上这整个流程都在穷举 应该全速运作也要十万个cycle以上
才能确定1 Byte的资料
3a.Speculative Execution
我不太确定正确的方法要不要应用speculative execution的指令
在这件事情需要用被动的指令speculativity还是主动指定为
speculative execution 但假设是的话 可以应用的范围为
无效的mem_load,原本会产生exception,
但是我可以用speculative execution,放在不会执行的if-else中
但CPU不具有足够条件做出正确的branch prediction的话,
在不执行那端的mem_load也会排入pipeline,并且在最後取消
volatile V = *Y
a = rdtsc()
if (V > 0)
else
{
b = load_mem(DUMMY)
c = load_mem(&X + 0)
}
a = rdtsc() - a
==>speculative execution化
volatile V = *Y
a = rdtsc()
SPEC_TRUE(V) { }
SPEC_FALSE(V)
{
b = load_mem(DUMMY)
c = load_mem(&X + 0)
}
a = rdtsc() - a
这时候CPU ooo会同时开始执行SPEC_TRUE与SPEC_FALSE的指令
最後SPEC_FALSE因为不成立,所以load_mem执行到中间就被取消
但这中间已经去Memory动作了 因此Cache也产生变化,但是取消
後不发exception,可能速度会加快很多 然後Host OS无法
侦测到你一直在产生GPF,降低被发现的机率
F.最後结论
以上的用法有需多前提条件 因此了解这个条件後有对应的话
可能可以避开.....对这没甚麽自信 降低发生问题的洞
1.电脑Cache读取的时间与外部记忆体差异巨大
现况一定是这样 未来也一定是 无解
2.rdtsc精确度太高 来个1000 cycle误差就行
或者限制仅kernel mode可以用(规格上已经支援 但为了相容性不开)
总之rdtsc要背太多旧程式相容性的锅..
3.直觉上,跑一个记忆体载入指令,应该要在合法的位置才启动啊
但实际上:
|TLB/PF |VALID|
|FETCH|DECODE|MEM-----|ADR |WRITE|
为了加速,计算Address合法性要经过TLB不比Memory回来快上多少
因此在检查的同时也发出了Memory 存取的功能,让两个一起发动
如果指令在MEM之前能检查完Address的合法性 连整个
MEM/Cache Stage都不启动的话则降低这种事情被分析跟被穷举的可能
4.上面的例子等於一个指令中有Indirect Memory的存取.但没有支援
这种指令的RISC并没有完全避掉问题 所以单一指令有没有MEM[MEM[ADR]]
这样的存取能力是不是重点就不知道了
--
※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 111.243.156.56
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/PC_Shopping/M.1515169257.A.E56.html
1F:推 kira925 : 推 01/06 00:25
2F:推 hizerg : 推 01/06 00:25
3F:推 royroy666 : 先推 01/06 00:29
4F:→ PlayStation3: JK神 01/06 00:30
5F:推 Shauter : JK最高 01/06 00:35
6F:推 s25g5d4 : 推 JK 神 01/06 00:41
7F:→ jk21234 : 3的描述有bug, X要是256 Byte的很多倍而且&X + 0 01/06 00:43
8F:→ jk21234 : 该知道我简化过不想修正回来了.. 01/06 00:45
9F:→ KotoriCute : jk神!先推再说 01/06 00:45
10F:推 ang728 : 好久没推 先推再说 01/06 00:49
11F:推 winiel559 : 推jk神 01/06 01:00
12F:推 Windcws9Z : 推 01/06 01:06
13F:推 jior : 快推,免得人家知道我是文组!! 01/06 01:09
14F:推 alexgame01 : 推 01/06 01:24
15F:推 saito2190 : 先推,资工肥宅快要看不懂了 01/06 01:43
16F:推 tyler930030 : 我也那麽认为呢 01/06 01:48
17F:推 ccc73123 : 这个理组也不一定看得懂好吗XD 01/06 01:59
18F:推 i9602283 : 看不懂,推 01/06 02:20
19F:推 ken841520 : 推,我开始觉得我4年CS白念了QQ 01/06 02:25
20F:→ jk21234 : 我大二计算机结构交作业就是用rdtsc提供cpu cache 01/06 02:28
21F:→ jk21234 : 资料 01/06 02:28
22F:推 Winux : 比较好奇这麽久的bug 怎麽会到现在才被找出来? 01/06 02:29
23F:→ Winux : 是因为这方法太蠢吗? 01/06 02:30
24F:推 ctes940008 : 推 01/06 02:34
25F:推 cory8249 : 推 Archi / OS 都快忘光了 QQ 01/06 02:36
26F:→ jk21234 : 想出2的例子的是好几年前就有但这样只能分析系统虚 01/06 02:39
27F:→ jk21234 : 拟机中 别人正在跑什麽程式 或者小机率猜正在加密 01/06 02:39
28F:→ jk21234 : 的资料可能是什麽 01/06 02:39
29F:→ jk21234 : 直到3的例子成立才会变资料能被分析走 01/06 02:40
30F:→ commandoEX : 所以是Intel挖坑自己跳 01/06 02:45
31F:推 bf000777966 : RDTSC本来就不该让低权限的APP使用,CPUID也是 01/06 03:23
32F:→ bf000777966 : 难怪有人说X86是个烂架构 01/06 03:31
33F:推 bf000777966 : 刚刚查了一下资料,RDTSC指令是可以禁止在CPL=3执 01/06 03:44
34F:→ bf000777966 : 行的,其实只要OS把这个指令禁止掉所有的问题不都 01/06 03:44
35F:→ bf000777966 : 解决了吗? 01/06 03:44
36F:推 pimachu : 快推 不然会被发现看不懂 01/06 04:03
37F:推 htps0763 : 感觉一直以来x86为相容性付出的成本太大了 01/06 04:13
38F:推 NCTUFAIWEN : 推 01/06 04:58
39F:→ quamtum : mem[mem[a+b]可以直接一条执行代表btb一猜错马上有 01/06 07:04
40F:→ quamtum : cache资料泄漏问题,包括in order cpu 01/06 07:05
41F:推 weichen5566 : 推了表示懂 01/06 07:05
42F:→ quamtum : 像clflush是cpl3可跑但wbinvd 只有cpl0可跑也蛮怪 01/06 07:07
43F:推 Jay915 : 推 01/06 08:01
44F:推 ken720331 : 推 01/06 08:14
45F:→ mensalord : 推了表示跨谋 01/06 08:27
46F:推 DKPCOFGS : 有推有懂 01/06 09:24
47F:推 b09134 : 我懂我懂… 01/06 09:32
48F:推 spfy : 没错 跟我想的...算了 01/06 10:18
49F:推 kipi91718 : 感谢分享,又更了解一些了! 这应该能拿到CS课堂上讲 01/06 11:22
50F:推 c60203 : 略懂略懂 可是电虾点在?( 被殴 01/06 11:49
51F:推 attis : 其实跟x86没有关系 纯粹是为了快略过检查导致这个漏 01/06 13:12
52F:→ attis : 洞 不然x86的amd没这个问题 risc的arm和A系列晶片有 01/06 13:12
53F:→ attis : 这个问题 01/06 13:12
54F:→ chinfu1222 : 赶快推 不然人家以为你文组看不懂 01/06 13:22
55F:推 dustlike : 只能推了 01/06 13:46
56F:推 kqalea : 最主要是cache的演算法问题 01/06 14:42
57F:→ kqalea : 不管是x86 ARM powerpc 或是各种DSP RISC 01/06 14:43
58F:→ kqalea : cache 演算法不外乎就是random , round robin 之类 01/06 14:46
59F:→ kqalea : 因为ASIC成本考量大部分人不可能实作一个很复杂的 01/06 14:48
60F:→ kqalea : 演算法去增加那1~5%效能或是安全性check 01/06 14:49
61F:→ kqalea : 最有效简单的方式就是一个够大够快fetch的cache 01/06 14:49
62F:→ kqalea : 用指令架构上的做法确保cache的安全性是合乎逻辑的 01/06 14:52
63F:→ kqalea : AMD跟ARM这次不受灾的原因在於他们很早就用比较新的 01/06 14:55
64F:→ kqalea : 演算法去处理cache coherence的问题 01/06 14:56
65F:→ kuma660224 : intel工程师睡了很久。 01/06 14:58
66F:推 kqalea : 若是相信阴谋论的话这个印该是intel故意不修复的 01/06 15:01
67F:推 hms5232 : 资管系路过 到2就看不太懂了zz 01/06 16:53
68F:推 SULAjardin : 理工组推 (前3行都看DER懂) 01/06 22:01
69F:→ eva19452002 : 靠北哦,这串讨论串到底是有多少神人啊? 01/06 23:00
70F:推 leeart20 : 看不懂的死肥宅来推…(滚走) 01/07 00:52
71F:推 david7112123: 推 01/07 01:00
72F:推 fuhu66 : 靠,最近计算机结构大爆发 01/07 04:57
73F:推 vvind : 这篇看不懂 01/11 11:36
74F:推 a1u1usul3 : 这篇讲得非常详细且清楚,感谢 01/11 14:58
75F:推 leo0519 : 台大计系先推 02/06 13:22