Qualcomm Securitybulletin CVE-2023-33029 漏洞分析
0x01 漏洞信息
description : Memory corruption in DSP Service during a remote call from HLOS to DSP.
根据漏洞描述来看,内存损坏是在 DSP 服务中发生的,具体的触发过程是 HLOS(主机操作系统)向DSP 发送请求并等待相应的过程中。
什么是DSP ?
全称是 Digital Signal Processor , DSP 是一种专门设计来处理数字信号的微处理器。一般在信号处理领域,如图像处理、语音识别等。
什么是HLOS?
HLOS (Host Operating System): 这通常指的是运行在设备主处理器上的操作系统,它负责管理和控制设备的硬件资源,并提供用户界面和服务。
代码库路径:
https://git.codelinaro.org/clo/la/kernel/msm-5.4/-/commit/d4b9e0d3bfcb5213e23f5642cb8dcc1433542303#7b5ee30919fc6e80fe7597966e29bdc13d262367
根据其修复的日志信息,可以分析出:
- Thread T1 add buffer to fl->cached_bufs and release fl->hlock and holding buffer reference.
- 线程T1将一个缓冲区(buffer)添加到
fl->cached_bufs
(可能是一个缓存缓冲区列表)中,然后释放fl->hlock
(可能是一个互斥锁),同时保持对缓冲区的引用。
- 线程T1将一个缓冲区(buffer)添加到
- Now thread T2 will acquire fl->hlock and free buffer in fastrpc_cached_buf_list_free().
- 现在,线程T2将获取
fl->hlock
,然后在fastrpc_cached_buf_list_free()
函数中释放缓冲区。
- 现在,线程T2将获取
- T1 will dereference the freed buffer.
- 线程T1将对已释放的缓冲区进行解引用(dereference)。
- Moving reference buffer uses for T1 inside fl->hlock to avoid UAF.
- 为了避免使用后释放(UAF,Use After Free)的错误,建议在
fl->hlock
内部为T1移动引用缓冲区。
- 为了避免使用后释放(UAF,Use After Free)的错误,建议在
0x02 漏洞相关函数
存在漏洞的函数fastrpc_buf_free
1 |
|
线程二要执行的函数 fastrpc_cached_buf_list_free
1 |
|
根据漏洞修复的情况来看,唯一的不同的是 buf->type 在修复后,移到了锁的保护中。
如果按照修复前的代码中,当前线程释放锁后,此时如果有其他的线程介入,可能会在当前线程设置buf->type 为 -1 之前,就将 buf 结构体进行释放,收回该结构体的内存区域,接着当前结构体会对 buf->type 解引用,从而造成 UAF 漏洞。
1 |
|
主要结构体
1 |
|
驱动的函数操作符号
1 |
|
定位驱动名称
DEVICE_NAME 的定义在 adsprpc_share.h 头文件内:
0x03 代码路径分析
线程一 的执行路径:
根据fastrpc_buf_free 函数中要到达漏洞分支中,cache 参数不能0,在代码中只能看到如下调用
fastrpc_buf_free(ctx->buf, 1) —>
context_free(struct smq_invoke_ctx *ctx) —>
fastrpc_context_list_dtor(struct fastrpc_file *fl) —>
fastrpc_file_free(struct fastrpc_file *fl) —>
fastrpc_device_release(struct inode *inode, struct file *file) —>
线程二 的执行路径:
fastrpc_cached_buf_list_free 路径分析
fastrpc_cached_buf_list_free(struct fastrpc_file *fl) —>
fastrpc_cached_buf_list_free 函数有两处调用
调用一,在 fastrpc_buf_alloc 函数中,需要进入到调用处,需要经过 IS_ERR_OR_NULL 判断指针,所以不是走到这个分支。
IS_ERR_OR_NULL
是Linux内核中一个常用的宏,用于检查一个指针是否表示一个错误或者为NULL
如果ptr
是错误代码指针或NULL,这个宏返回true(非零值),否则返回false(零值)
调用二,fastrpc_file_free 函数中,可以看到在这里会分别调用 fastrpc_context_list_dtor 函数和 fastrpc_cached_buf_list_free 函数。
fastrpc_file_free —->
fastrpc_file_free 函数也有两处调用
调用一, fastrpc_device_release 函数中调用,这和上面线程1 执行的路径一样了,大概是使用这个调用。,因为这个调用释放的结构体和线程1 是一致的。
调用二,fastrpc_file_list_dtor(struct fastrpc_apps *me) 函数中调用,然后fastrpc_file_list_dtor 会被
fastrpc_device_exit函数调用,这是驱动退出时要执行的函数。
0x04 漏洞触发原理
这个漏洞跟blackhat 内的NPU CVE-2023-33114 类似,都是条件竞争引发的UAF。我是先看完CVE-2023-33114 后,再分析的本漏洞。
由于漏洞是条件竞争引发的UAF,按照代码路径分析的思路,整个的条件竞争如下图所示:
- 线程一 在执行到 fastrpc_buf_free(ctx->buf, 1) 内的 spin_unlock 对 &fl 解锁,然后立马线程二在竞争时间内获取到对 &fl 的加锁。
- 然后线程二会调用 fastrpc_buf_free(free,0) 来直接 对buf 内存直接释放。
- 最后线程一对 buf 结构体内的指针解引用。但由于在线程二内,已经将buf 结构体的内存空间释放了,所以对 buf ->type 进行解引用时,会操作未知的内存空间,从而导致内存损坏的问题。
分析到这里,整个漏洞的触发流程相当苛刻。
首先是漏洞触发流程的并发,需要多线程执行close 函数,这就意味着调用了close 函数后,要重新调用open函数打开驱动,并不能和ioctl 一样一直不停的调用。
另外在 线程一和线程二 的执行流程中,都会执行fastrpc_file_free 函数内的 fastrpc_context_list_dtor 函数和 fastrpc_cached_buf_list_free 函数,这两个函数会先后执行。
所以线程二在执行close 的时候,也会执行fastrpc_context_list_dtor 函数,这就意味着,线程二要先走完线程一的流程,然后线程一调用fastrpc_context_list_dtor 函数执行到fastrpc_buf_free内对 &hf-hlock 进行解锁,然后线程二才能执行到fastrpc_cached_buf_list_free 函数,走完接下来要触发的条件竞争。