Linux内核AF_VSOCK套接字前提协作缝隙(CVE-2021-26708)阐发

宣布时候 2021-03-10

缝隙背景


近期,外洋宁静研讨职员在oss-security上表露了一个AF_VSOCK套接字前提协作高危缝隙CVE-2021-26708(CNVD-2021-10822、CNNVD-202102-529)。按照表露细节,该缝隙是因为毛病加锁致使,能够在低权限下触发并主动加载易受进犯驱动模块建立AF_VSOCK套接字,进而致使本地权限晋升。该缝隙补丁已归并到Linux内核主线中。


VSOCK先容和架构


VSOCK先容


VM套接字最早是由Vmware开辟并提交到Linux内核主线中。VM套接字许可假造机与假造机办理法式之间停止通讯。假造机和主机上的用户级利用法式都能够利用VM 套接字API,从而增进guest假造机与其host之间的疾速有用通讯。该机制供给了一个vsock套接字地点系列及其vmci传输,旨在与接口级别的UDP和TCP兼容。VSOCK机制随即获得Linux社区的呼应,Redhat在VSOCK中为vsock增加了virtio传输,QEMU/KVM假造机办理供给撑持,Microsoft增加了HyperV传输。


VSOCK架构


VM套接字与其余套接字范例近似,比方Berkeley UNIX套接字接口。VM套接字模块撑持面向毗连的流套接字(比方TCP)和无毗连数据报套接字(比方UDP)。VM套接字和谈系列界说为“AF_VSOCK”,并且套接字操纵分为SOCK_DGRAM和SOCK_STREAM。以下图所示:


1.png


VSOCK撑持socket API。AF_SOCK地点簇包罗两个因素:CID和port。CID为ContextIdentifier,高低文标识符;port为端口。TCP/IP利用法式几近不须要变动就能够适配,每个地点表现为。另有一层为transport,VSOCK transport用于完成guest和host之间通讯的数据通道。以下图所示:


2.png


Transport按照传输标的目的分为两种(以SOCK_STREAM范例为例),一种为G2H transport,表现guest到host的传输范例,运转在guest中。另外一种为H2G transport,表现host到guest的传输范例。以QEMU/KVM传输为例,以下图所示:


3.png


该传输供给套接字层接口的驱动分为两个局部:一个是运转在guest中的virtio-transport,用于共同guest停止数据传输;另外一个是运转在host中的vhost-transport,用于共同host停止数据传输。VSOCK transport还供给多传输通道形式,该功效是为了撑持嵌套假造机中的VSOCK功效。以下图所示:


4.png


撑持L1假造机同时加载H2G和G2H两个传输通道,此时L1假造机便是host也是guest,经由进程H2G传输通道和L2嵌套假造机通讯,经由进程G2H传输通道和L0 host通讯。VSOCK transport还撑持本地环回传输通道形式,不须要有假造机。以下图所示:


5.png


该形式用于测试和调试,由vsock-loopback供给撑持,并对地点簇中的CID停止了分类,包罗两种范例:一种是VMADDR_CID_LOCAL,表现本地环回;一种为VMADDR_CID_HOST,表现H2G传输通道加载,G2H传输通道未加载。

 

缝隙阐发与触发进程


缝隙阐发


该缝隙触发缘由是毛病加锁致使前提协作,按照补丁可知,存在多处毛病加锁,这里以vsock_stream_setsockopt()函数补丁为例,以下图所示:


6.png


补丁很简练,将第1564行代码挪动到第1571行,中心就隔着第1569行代码:lock_sock(sk)。加锁前,vsk->transport已赋值到transport变量中,这里发生了一个援用,而后才停止lock_sock(sk)将sk锁定。可是vsk->transport会在多处被挪用乃至被开释,这就有能够经由进程前提协作形成Use After Free。


触发进程


起首找到点窜或开释vsk->transport的挪用途径,来看关头函数vsock_assign_transport()的完成。对多传输形式,该函数用于按照差别CID分派差别的传输通道。完成代码以下图所示:


7.png


按照sk->sk_type分为SOCK_DGRAM和SOCK_STREAM,在SOCK_STREAM中,分为三种传输通道。这里能够经由进程将CID设置为本地环回形式,获得transport_local传输通道。接上去以下图所示:


8.png


若是vsk->transport不为空,则进入if语句。先判定vsk->transport是不是即是new_transport,若是即是间接前往,在触发进程中,要保障能走到vsock_deassign_transport()函数,该函数是析构函数,用于开释transport。以下代码所示:


9.png


行411,挪用vsk->transport->destruct(),要明白利用transport范例,前文已肯定利用transport_local。Transport_local为全局变量,会在vsock_core_register()函数中被初始化。该函数被挪用情况以下图所示:


10.png


*_init()函数用来初始化transport的回调函数,按照第二局部先容,vhost_vsock_init()、virtio_vsock_init()和vsock_loopback_init()函数为QEMU/KVM情况下的撑持函数。咱们发明transport->destruct()函数的最初完成都是统一个函数。以下图所示:


11.png


该destruct()函数开释vsk->trans,以下图所示:


12.png


而vsk->trans指针是指向transport的。布局体vsock_sock界说以下所示:


13.png


终究能够机关一个开释transport的函数途径为:vsock_stream_connect-> vsock_assign_transport->virtio_transport_destrcut。


找到了开释途径,下一步找利用途径,virtio_transport_notify_buffer_size()函数会利用transport。以下图所示:


14.png


第492行,经由进程vsk->trans获得指向transport的指针,第497行,解援用vvs指针,对vvs->buf_alloc停止赋值。而挪用virtio_transport_notify_buffer_size()函数终究会被vsock_stream_setsockopt()函数挪用。终究能够机关一个利用transport的函数途径为:vsock_stream_setsockopt-> vsock_update_buffer_size->virtio_transport_notify_buffer_size。


接上去便是营建一个抢锁的前提协作情况,很较着必须是connect()体系挪用先抢到锁对transport停止开释,而后再挪用setsockopt()能力触发缝隙。有开辟职员提出利用userfaultfd机制先将lock_sock锁定,而后在去开释锁,停止前提协作。缝隙触发进程以下图所示:


15.png


蓝框中是connect()挪用进程,最初挪用virtio_transport_destruct()函数开释vsk->trans。红框中是setsockopt()挪用进程,挪用virtio_transport_notify_buffer_size()函数利用vvs,该值是0xffff888107a74500,在0xffff888107a74500+0x28处会写入4字节。


参考链接:

[1]http://github.com/torvalds/linux/commit/d021c344051af91f42c5ba9fdedc176740cbd238

[2]http://static.sched.com/hosted_files/devconfcz2020a/b1/DevConf.CZ_2020_vsock_v1.1.pdf

[3]http://github.com/jordan9001/vsock_poc

[4]http://terenceli.github.io/%E6%8A%80%E6%9C%AF/2020/04/18/vsock-internals


启明星斗主动进攻尝试室(ADLab)


ADLab建立于1999年,是中国宁静行业最早建立的攻防手艺研讨尝试室之一,微软MAPP打算焦点成员,“黑雀进犯”观点首推者。停止今朝,ADLab已由进程CVE累计宣布宁静缝隙近1100个,经由进程 CNVD/CNNVD累计宣布宁静缝隙1000余个,延续坚持国际收集宁静范畴一流水准。尝试室研讨标的目的涵盖操纵体系与利用体系宁静研讨、智能终端宁静研讨、物联网智能装备宁静研讨、Web宁静研讨、工控体系宁静研讨、云宁静研讨。研讨功效利用于产物焦点手艺研讨、国度重点科技名目攻关、专业宁静办事等。


微信图片_202.jpg