Qemu-KVM虚拟化逃逸0Day漏洞修复(CVE-2020-14364)
一、漏洞简介
背景:近日,我们操作系统虚拟化团队通过集团安全部获悉Qemu-KVM组件存在重大高危逃逸漏洞(CVE-2020-14364),此漏洞的类似攻击方式是在2019年某网络安全大赛中出现的数组越界攻击手段。
漏洞原理:漏洞类型为数组越界读写,越界后读取某堆后的0xffffffff的内容,从而强行终止虚拟化进程,进而实现虚拟化逃逸。属于高危漏洞,影响极广。
利用方式:此攻击方式比较简单,攻击难度较低,攻击者只需要拥有一台云环境上的虚拟机,便可以利用该漏洞获取敏感数据信息,甚至提权宿主机root权限,进而攻击虚拟机所在资源池所有租户主机,还有可能通过已开通的内网权限攻击管理域系统。风险极高,影响极大。目前该漏洞经测试在主流云平台均存在该问题。
影响范围:该漏洞会攻击Qemu-KVM 1.0 以上的全部版本,几乎涉及所有Openstack云厂商,影响范围极广。
二、攻击介绍
漏洞存在与./hw/usb/core.c中。因为libvirt启动的虚拟机默认会有usb设备连接,而任何usb接口(如uhci,ehci,xhci)与usb设备(如usb-tablet,usb-mouse等)之间交互都会经过core.c文件中的usb_process_one函数。而usb_process_one中可能进入的两个分支do_parameter和do_token_setup均存在一个问题:在检查最终需要使用的长度前已经提前设置了s->setup_len。
可以看出,在长度检查未通过的情况下并未将s->setup_len改为0,从而导致之后的do_token_in与do_token_out越界读写了s->data_buf这个数组。
在执行poc测试程序时,会发现有如下报错信息,在数组越界读写之后,触发了assert断言异常,进一步导致虚机发生崩溃:
usb_generic_handle_packet: ctrl buffer too small (65535 > 4096)
qemu-kvm: hw/usb/core.c:429: usb_handle_packet: Assertion `p->stream || !p->ep->pipeline || ((&p->ep->queue)->tqh_first == ((void *)0))' failed.
2020-08-16 08:01:21.074+0000: shutting down, reason=crashed
三、修复方式
3.1修复原理
基于上述的分析,本问题的解决方法就是当s->setup_len > sizeof(s->data_buf)时对s->setup_len的值进行重置,即分别在两个长度判断错误的情况下清空setup_len并重置setup_state状态值。
3.2实施方案的选择
经过方案论证,我们提出了采用版本升级及热补丁的修复方案,既针对所有qemu-kvm进程,采用软件包版本升级+存量虚机热补丁的方式。
优点:效率高,见效快,能够极大的减轻运维压力,提升问题的修复速度;
缺点:
1)如果虚机负载过高,容易导致虚机挂起时间过长,影响用户业务;
2)涉及到的qemu-kvm 1.0以上版本数量众多,时间不足,给热补丁的研发工作带来了巨大的挑战;
3)部分qemu-kvm软件包由于时间过去太久,维护不完备等原因,并未保留完整的源码包、debuginfo包等原始介质,导致制作热补丁难度指数级提升;
初步总结
大云虚拟化团队针对线上运行的系统特点,推出了热补丁的修复方案,可以在不重启系统的前提下修复此漏洞,保障了用户的业务不中断,也不会造成影响。面对这种0-DAY漏洞,热补丁方式当仁不让,可以大大提升问题的修复速度。
3.3修复步骤
1)升级Qemu-KVM
大云虚拟化团队在第一时间跟进了此漏洞信息,并发布了安全更新公告,订阅了BC-Linux系统服务的客户均会受到相关的更新公告提醒。
详细的安全更新内容如下:
系统版本 | 热补丁支持情况 | 漏洞修复版本 |
BC-Linux 7.1 | 支持 | qemu-kvm-1.5.3-507.el7.centos.bc.x86_64 |
BC-Linux 7.3 | 支持 | qemu-kvm-rhev-2.6.0-29.2.4.el7.15.3.6.x86_64 |
BC-Linux 7.4 | 支持 | qemu-kvm-rhev-2.9.0-16.1.el7_4.bclinux.14.1.x86_64 |
BC-Linux 7.5 | 支持 | qemu-kvm-rhev-2.10.0-21.5.el7_5.bclinux.7.x86_64 |
BC-Linux 7.6 | 支持 | qemu-kvm-rhev-2.12.0-18.4.el7_6.bclinux.6.3.x86_64 |
BC-Linux 7.7 | 支持 | qemu-kvm-rhev-2.12.0-33.12.el7.bclinux_7.8.x86_64 |
对于使用了BC-Linux系统的用户,可以参考上述的公告信息中的步骤,通过yum命令自动对Qemu-KVM进行升级,如果未使用热补丁方案需硬重启虚机系统生效漏洞修复功能;
2)安装upatch用户态工具和补丁包
下载并安装大云虚拟化团队提供的BC-Linux 7系统下用户态程序热补丁管理工具:
bclinux-upatch-0.1.4-2.el7.hotfix.3.x86_64.rpm
3)为Qemu-KVM打上热补丁
首先先检查一下当前系统的热补丁信息:
[root@bclinux-vm1 ~]# upatch-ctl info
通过upatch-ctl服务为qemu-kvm应用程序打上热补丁
[root@bclinux-vm1 ~]# upatch-ctl patch -p -1
再次查看热补丁的应用情况:
[root@bclinux-vm1 ~]# upatch-ctl info
4)验证热补丁是否生效
除了通过upatch-ctl info命令查看热补丁应用情况外,同时我们也可以采用内部非公开的POC测试程序验证漏洞是否已修复,确保热补丁的有效性。
3.4遇到的问题
1)热补丁工具的bug
我们在制作qemu–kvm 2.12补丁的过程中,定位到原生热补丁工具中的编译器不兼容gcc新选项-iquote的问题,导致补丁制作失败。
我们迅速的修复了原生热补丁工具存在性能低、不稳定等问题,顺利为2.12版本qemu制作了热补丁。
2)打补丁过程的效率提升
我们发现,针对现网普通4G内存的虚机,在给qemu进程打热补丁的时候,热补丁瞬间加载生效。但是现网存在一些64G、128G的大规格虚机,甚至挂载了2T硬盘且业务繁忙的数据库业务。
在前期原生热补丁工具的使用过程中,我们发现对于这样大规格的虚机,原生热补丁工具在打补丁的过程中可能耗时达到半个小时,我们经过深入的分析,引入了一些优化手段,将大规格、高负载的虚机的打补丁的操作时间优化到了1分钟之内完成操作:
不过,对于Openstack大规模集群下的qemu组件打热补丁,在极端情况下需要1分钟左右,仍然不是我们需要的最佳的结果,因此,我们紧急对热补丁加载工具做了更深入的优化,使大规格虚机的热补丁加载效率进一步提升96% ,时间缩短到2秒以内,用户对hypervisor层打热补丁操作几乎无感知。
3)古老版本的代码文件遗失
我们在制作热补丁的过程中,发现个别环境使用的古老的qemu-kvm软件包(5、6年前的包),已经无法找到原始的src包、安装包等等素材,导致无法直接调用热补丁工具生成热补丁。
为了解决这个问题,我们尝试跳过src包,直接通过debuginfo文件中的符号表,查找目标函数在原程序中的地址,并修改热补丁文件中对应函数的符号值。从而实现了热补丁文件的制作。
PS:这种方法存在一定的打补丁失败的风险性,并不是“万能钥匙”。
四、总结
本次发现的这个QEMU-KVM(CVE-2020-14364)漏洞,利用方式简单,后果严重,影响面非常的大,它可以突破虚机与宿主机、虚机与虚机之间的安全边界(以往我们发现的一些漏洞更多是存在于用户态层面),大云虚拟化团队第一时间响应了相关问题,并针对线上环境出具了热补丁方案,在2天的时间内,完成6万+虚机的修复,整个过程用户无任何感知,保证了用户业务的持续稳定的运行。
By 中国移动大云虚拟化团队