Meltdown
漏洞暴发之后,各云厂商已陆陆续续升级宿主机,升级Guest
是否有较大的性能影响, 是否应该升级Guest
虚拟机等问题又困扰着云租户们。
本文基于实例来分析Guest
虚拟机的性能影响。
首先来看Meltdown
的原理。现代CPU架构在不同的安全等级运行指令。内核需要直接操作硬件,运行于最高权限,而几乎所有的应用程序都运行于各低权限上。用户态进程通过系统调用访问内核数据。一般情况下,CPU在执行时使用虚拟内存地址,内核使用页表来控制虚拟内存与物理内存的映射。用户态进程不能访问映射给内核的内存页。这些映射关系的计算较为耗时,因而CPU使用TLB(Translation lookaside buffer)
来存储计算后的映射关系。从TLB
中移除这些映射再重新计算并缓存会消耗性能,因而内核实现上会尽可能减少刷新TLB,于是内核将用户态和内核的数据都映射进用户态页表中。正常情况下,这不存在安全风险,页表的权限可以阻止用户态进程访问内核数据。
现代CPU追求运行速度,会从所有的内存映射关系中预取数据,而CPU本身会乱序执行,且乱序执行时不会验证是否有权限访问内存,且CPU缓存不会被恢复,因而Meltdown
的研究者构造乱序执行的场景将内核内存地址的内容获取到CPU缓存中,再通过侧信道攻击获取到相应内容。
Linux内核采用KPTI(Kernel Page Table Isolation)
机制,将内核页表和用户空间页表隔离开,避免CPU在预取和乱序执行时用户态进程时获取到内核页表中的数据,从而缓解Meltdown
利用。
这样当进程用户在用户空间时,使用用户态页表,发生中断或者异常陷入内核时,将切换到内核页表。页表的切换将导致性能下降。
Intel在Haswell
架构后增加了一个特性叫做PCID(Process-Context Identifiers)
。在没有该特性时,切换页表时将需要刷新整个TLB
,而在CPU支持PCID时,内核用不同ID来区分两个页表将其关联PCID不再需要刷新整个TLB,这样会大大减小页表切换带来的性能损失。
在Linux中查看PCID
的方法:
1 | cat /proc/cpuinfo |grep pcid |
根据上述分析,如果Guest
虚拟机的CPU支持PCID
,则KPTI
引发的性能下降应会更小一些。。VMware ESXi
平台上的Guest
虚拟机CPU支持PCID
,而KVM平台上Guest
虚拟机CPU是否支持PCID
由QEMU/KVM
进程的-cpu
选项决定。
查看KVM支持的CPU选项:
1 | root@dummy:~# /usr/bin/kvm -cpu help |
若需要Guest
支持PCID
, 启动QEMU/KVM
进程时,需要将-cpu
选项设置为Haswell
, Broadwell
或者使用host-model
,host-passthrough
等模式。
在我们的KVM平台创建了一台CentOS6.8
的Guest
虚拟机来验证一下升级更新支持KPTI后在是否支持PCID两种情况下的性能影响。
测试方式为记录在该虚拟机上执行编译内核的时间,测试两种情况:
- 原生内核
- 支持
KPTI
的内核,升级完后内核版本为:2.6.32-696.18.7.el6.x86_64
在虚拟机CPU不支持PCID
的情况下测试结果如下:
1)原生内核:
1 | real 10m10.618s |
KPTI
内核:升级后性能下降约9.8%。1
2
3real 11m10.861s
user 9m51.371s
sys 1m22.248s
在虚拟机CPU支持PCID
的情况下测试结果如下:
1)原生内核:
1 | real 10m24.469s |
KPTI
内核:1
2
3real 10m40.750s
user 9m19.495s
sys 1m11.286s
升级后性能下降约2.5%
从我们的实例可以看到,Guest
虚拟机CPU是否支持PCID
对于性能下降有较大影响。
若用户的Guest
虚拟机CPU不支持PCID
可与云提供方沟通,并根据实际业务负载进行性能影响评估,综合考虑安全与性能决定是否升级更新Guest虚拟机。
在升级完Guest性能测试不理想的情况下,也可以在内核启动参数加添加noibrs noibpb nopti
等参数禁用该特性。