linux内核竞争条件漏洞,Linux内核AF_VSOCK套接字条件竞争漏洞(CVE-2021-26708)分析...

漏洞背景

近期,国外安全研究人员在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。如下图所示:

ff51786f952d4f16b558eb32f02f73e5.png

VSOCK支持socket API。AF_SOCK地址簇包含两个要素:CID和port。CID为ContextIdentifier,上下文标识符;port为端口。TCP/IP应用程序几乎不需要更改就可以适配,每一个地址表示为。还有一层为transport,VSOCK transport用于实现guest和host之间通信的数据通道。如下图所示:

49902a0f50343ba6f9c432b16d290073.png

Transport根据传输方向分为两种(以SOCK_STREAM类型为例),一种为G2H transport,表示guest到host的传输类型,运行在guest中。另一种为H2G transport,表示host到guest的传输类型。以QEMU/KVM传输为例,如下图所示:

1a589eb76ad238f46ef7373677959c20.png

该传输提供套接字层接口的驱动分为两个部分:一个是运行在guest中的virtio-transport,用于配合guest进行数据传输;另一个是运行在host中的vhost-transport,用于配合host进行数据传输。VSOCK transport还提供多传输通道模式,该功能是为了支持嵌套虚拟机中的VSOCK功能。如下图所示:

84c02b8a27e1294f791d11912b18b221.png

支持L1虚拟机同时加载H2G和G2H两个传输通道,此时L1虚拟机即是host也是guest,通过H2G传输通道和L2嵌套虚拟机通信,通过G2H传输通道和L0 host通信。VSOCK transport还支持本地环回传输通道模式,不需要有虚拟机。如下图所示:

782b2c637711d3e33eaaf2bdeab8ecec.png

该模式用于测试和调试,由vsock-loopback提供支持,并对地址簇中的CID进行了分类,包含两种类型:一种是VMADDR_CID_LOCAL,表示本地环回;一种为VMADDR_CID_HOST,表示H2G传输通道加载,G2H传输通道未加载。

漏洞分析与触发过程

漏洞分析

该漏洞触发原因是错误加锁导致条件竞争,根据补丁可知,存在多处错误加锁,这里以vsock_stream_setsockopt()函数补丁为例,如下图所示:

501eeac053406639e7c3ebac0f6d4770.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分配不同的传输通道。实现代码如下图所示:

85f7f78ef438613598f5633cecae32b8.png

根据sk->sk_type分为SOCK_DGRAM和SOCK_STREAM,在SOCK_STREAM中,分为三种传输通道。这里可以通过将CID设置为本地环回模式,得到transport_local传输通道。接下来如下图所示:

2e444f2e9dcd66fb221291f588dbacac.png

如果vsk->transport不为空,则进入if语句。先判断vsk->transport是否等于new_transport,如果等于直接返回,在触发过程中,要保证能走到vsock_deassign_transport()函数,该函数是析构函数,用于释放transport。如下代码所示:

8ec421f88569521969856f55253fad4c.png

行411,调用vsk->transport->destruct(),要明确使用transport类型,前文已经确定使用transport_local。Transport_local为全局变量,会在vsock_core_register()函数中被初始化。该函数被调用情况如下图所示:

3df26ca8ffd8c2859d3aa22337333b41.png

*_init()函数用来初始化transport的回调函数,根据第二部分介绍,vhost_vsock_init()、virtio_vsock_init()和vsock_loopback_init()函数为QEMU/KVM环境下的支持函数。我们发现transport->destruct()函数的最后实现都是同一个函数。如下图所示:

5880fc79445373aee5a717bf60a86c65.png

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

177f92b17efe19806390ee74970d374e.png

而vsk->trans指针是指向transport的。结构体vsock_sock定义如下所示:

deccdda1eccc0ad664beee8085929fe8.png

最终可以构造一个释放transport的函数路径为:vsock_stream_connect-> vsock_assign_transport->virtio_transport_destrcut。

找到了释放路径,下一步找使用路径,virtio_transport_notify_buffer_size()函数会使用transport。如下图所示:

f80e530f10b7af60b6c1f90b25159a55.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锁定,然后在去释放锁,进行条件竞争。漏洞触发过程如下图所示:

be733c74836544c4377d4722bb61db51.png

蓝框中是connect()调用过程,最后调用virtio_transport_destruct()函数释放vsk->trans。红框中是setsockopt()调用过程,调用virtio_transport_notify_buffer_size()函数使用vvs,该值是0xffff888107a74500,在0xffff888107a74500+0x28处会写入4字节。

参考链接:

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

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

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

[4]https://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安全研究、工控系统安全研究、云安全研究。研究成果应用于产品核心技术研究、国家重点科技项目攻关、专业安全服务等。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值