-
-
[原创]CVE-2024-0582 内核提权详细分析
-
发表于: 2025-6-30 15:10 3687
-
漏洞编号: CVE-2024-0582
影响版本: v6.4 < Linux Kernel < v6.6.5
漏洞产品: linux kernel - io_uring & io_unregister_pbuf_ring & uaf
利用效果: 本地提权

复现环境:qemu + linux kernel v6.5.3
环境附件: mowenroot/Kernel
复现流程: 执行exp后,账号:hacker的root用户被添加。su hacker完成提权。

漏洞本质是 uaf。从内核版本 5.7 开始,为了便于管理不同的缓冲区集,io_uring 允许应用程序注册由组 ID 标识的缓冲区池。通过 io_uring_register的 opcode->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。

「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 即可。
「1」 返回 ID 对应的 io_buffer_list(bl)。 当 ID 符合限制的时候,会使用数组来管理 io_buffer_list ,这个时候直接返回 ID对应的 bl 即可。如果超过限制,则使用xarray 来管理。
「1」 为 io_uring_buf_ring 申请空间 。 buf_ring 环存放 ring_entries 个 io_uring_buf_ring,而 io_uring_buf_ring 中存放地址、长度等信息。值得注意的是:申请 pages 为复合页。