CVE-2024-0582 内核提权详细分析
默文 二进制安全 333浏览 · 2025-03-11 09:53

CVE-2024-0582 内核提权详细分析

漏洞简介

漏洞编号: CVE-2024-0582

影响版本: v6.4 < Linux Kernel < v6.6.5

漏洞产品: linux kernel - io_uring & io_unregister_pbuf_ring & uaf

利用效果: 本地提权

image.png


环境搭建

复现环境:qemu + linux kernel v6.5.3

环境附件: mowenroot/Kernel

复现流程: 执行exp后,账号:hacker的root用户被添加。su hacker完成提权。

image.png


漏洞原理

漏洞本质是 uaf。从内核版本 5.7 开始,为了便于管理不同的缓冲区集,io_uring 允许应用程序注册由组 ID 标识的缓冲区池。通过 io_uring_registeropcode->IORING_REGISTER_PBUF_RING调用 io_register_pbuf_ring() 来完成注册ID标识缓冲区。并从内核版本 6.4 开始,io_uring 还允许用户将提供的缓冲区环的分配委托给内核,由 IOU_PBUF_RING_MMAP标识符即可生成。调用 IOU_PBUF_RING_MMAP 由内核完成分配空间后,然后使用 mmap()标识符映射到用户的地址,但是这个操作不会修改页面结构(pgae)的引用计数,然后使用 io_unregister_pbuf_ring()释放申请的空间的时候会调用 put_page_testzero(page),对 page 引用-1并判断引用是否为 0,如果为 0 就会释放 page ,因为 mmap 映射的时候并不会页面结构(pgae)的引用计数,内核并不知道是否取消了内存的映射。所以就会出现映射未取消就释放 page 的情况,而导致用户虚拟地址对物理地址映射未取消的 UAF

漏洞分析

关于io_uring的一些基础知识之前的文章已经详细介绍过,如果师傅们感兴趣可以看看之前的文章。接下来只介绍漏洞相关的点。

NVD描述:A memory leak flaw was found in the Linux kernel’s io_uring functionality in how a user registers a buffer ring with IORING_REGISTER_PBUF_RING, mmap() it, and then frees it. This flaw allows a local user to crash or potentially escalate their privileges on the system.

io_uring_register 提供了接口 io_register_pbuf_ring 来完成注册 ID 标识缓冲区。旨在通过 ID 来对不同的缓冲区进行管理。下面分析的 kernel 源码版本为 v6.5.3

image.png


io_register_pbuf_ring

「1」 首先把用户数据复制到内核的 reg。然后参数检查,判断 entries 是否为 2 次幂,并且限制 entries 最大不能超过 65536。需要注意一点:意味着条目最大为 32768

「2」 如果 ctx->io_bl 为初始化时,会尝试初始化 ctx->io_bl,这里的 io_bl是一个 64 长度的数组。数组中存放 io_buffer_list。如果 id 大于等于 64 时就会通过 xarray 来管理。

「3」 调用 io_buffer_get_list() ,通过 id 获取对应 bl (buf list),如果 bl 为空时,则会申请结构体 io_buffer_list 空间,标志为 GFP_KERNEL

「4」 当使用 IOU_PBUF_RING_MMAP 时,会调用 io_alloc_pbuf_ring(),来申请 buf_ring 空间,否则内存页,最后将 bl加入到ctx中。

使用 IOU_PBUF_RING_MMAP 就会完成对 buf_ring 的空间分配,全程都由内核来完成,不同于 io_sqe_buffers_register 需要用户传入注册的地址。用户只需要指定对应注册的 ID 即可。

io_buffer_get_list

「1」 返回 ID 对应的 io_buffer_list(bl)。 当 ID 符合限制的时候,会使用数组来管理 io_buffer_list ,这个时候直接返回 ID对应的 bl 即可。如果超过限制,则使用xarray 来管理。

io_alloc_pbuf_ring

「1」 为 io_uring_buf_ring 申请空间 。 buf_ring 环存放 ring_entriesio_uring_buf_ring,而 io_uring_buf_ring 中存放地址、长度等信息。值得注意的是:申请 pages 为复合页。

io_uring_buf、io_uring_buf_ring 结构体



io_unregister_pbuf_ring

「1」 先根据 id 获取 io_buffer_list,如果 id 符合标志则调用 __io_remove_buffers 仅仅释放 bl->buf_ring 。而不符合标准的使用 xarray 来管理,会直接释放整个 bl

__io_remove_buffers

「1」 由 IORING_REGISTER_PBUF_RING 申请的空间,会先获取 bl->buf_ring 的虚拟地址,然后调用 put_page_testzero(),对 page 引用 -1,如果当前引用==0,则释放 page,但是使用 mmap 映射持有时,不会对 page 引用改变,内核无法知道此时映射是否取消。



漏洞复现

本质就是篡改filp->f_mode为可写,然后篡改/etc/passwd

〔1〕 初始化:绑定CPU,注册io_uring,设置最大可打开文件数 (把rlim_cur设置为rlim_max),nr_files 最大打开 file 数量。

〔2〕 通过 IOU_PBUF_RING_MMAP 注册对应 IDbuf_ring区域。然后通过 mmap 映射到用户空间。

〔3〕 通过 io_uring_unregister_buf_ring 释放申请的所有 buf_ring

〔4〕 喷射 nr_files/etc/passwd,因为通过 O_RDONLY 标识符打开,f_mode 固定为 0x494a801d

〔5〕 尝试使用 UAF,通过固定的 f_flags+f_mode == 0x484a801d00008000 定位到文件处,修改f_mode

〔6〕因为无法知道文件描述符,所以暴力对所有/etc/passwd 进行写操作,通过返回值判断是否写入成功,非常稳定。


2 条评论
某人
表情
可输入 255