也来蹭个热度。
从没想到过,像CPU这样浓眉大眼的硬件也会成了叛徒!且这次事件影响之深、范围之广、修复之难,是以前各种OS级漏洞完全无法比拟的。
先说两个概念,一个是CPU缓存Cache,一个是CPU指令的乱序执行;
第一个,缓存的概念不用多说,就是在CPU里面有个临时存储器,比普通的内存小,但是快很多,供CPU高速访问用;
第二个,乱序执行,现代CPU为了提高性能,采用乱序执行(Out-of-OrderExecution)和预测执行(Speculative Prediction)。也就是不按程序的逻辑顺序执行,提前执行后面的命令。但提前执行的结果并不会输出,等全最后汇总才输出。万一乱序的指令错了,把错误的结果丢了就好了。
这样既能够提高性能,又可以保证正确结果,完美吧!但是,就是一个小小的点,丢弃CPU错误结果时,会恢复CPU的状态,但不会清楚CPU缓存的内容,而这两组漏洞正是利用了这一设计上的小点进行攻击的。
废话不多说,下面举个栗子,看看Spectre是如何实现的。
------------------------------分割线-------------------------------
(为便于理解,这里省略了进程地址与物理内存地址的变换)
假设Firefox在内存空间0x5000:0000存放了登录密码“Password”,"P"的ASCII码为80(十进制)。
下面是示例程序(不要纠结语法啊,俺不是程序猿)
byte[] Buff1=new byte[16]
byte[] Buff2=new byte[0x200000]
Buffsize = 16
N = 8192
...
if (x
y = Buff2[Buff1[x]*N]
当CPU执行" if (x
显然,Buffer1[0x40000000]这个访问明显是越界了,SoWhat!CPU不在乎,反正这是预执行,不费那个劲检查了,等汇总输出结果时,真发现错了再干掉他就成。
于是,Buffer1[0x40000000]虽然越界了,还是读到了地址0x50000000的值"P",也就是十进制的80。
接下来,把Buffer2[80*N]内存中的内容调入CPU到的缓存(这里的N,应该是与调入缓存页的大小相关)
到了结果汇总的时候了,x
到此都没问题,CPU架构的设计者该得意了,哥早就说过预执行时不需要检查了;哪怕万一这句真的执行了,这时候自然系统会检查到越界,哥再干掉它就行,反正程序别想拿到这个"P"。
但问题来了,前面说过,预执行指令被恢复时,CPU的缓存并未被恢复。然并卵啊,Spectre还是没法读到“P”呀。
这时就用到测信道攻击方式了,Spectre根本不用去读"P"的位置,只要正常去读取Buff2里的每个N位置的内容,测量读取的时间(缓存中的内容比内存中的快很多),就会发现第80个N位置的内容肯定比其他的要快很多,这样,值80,也就是"P"被解读出来了。
即便不知到密码存放的准确位置也没关系,改变x的值,反复执行,就能够读到内存中的每一个Byte,等于做了MemoryDump出来。
那位看官说了,你吹这么牛B,你做个程序出来验证下啊!Sorry,哥不是程序猿,就是看篇文章画个图。时间特仓促,不对的地方大家指正!【抱拳】
引用:
https://meltdownattack.com/
https://googleprojectzero.blogspot.co.at/2018/01/reading-privileged-memory-with-side.html
领取专属 10元无门槛券
私享最新 技术干货