当前位置: 首页 > news >正文

kernel源码分析 do_msgsnd read_msg

 笔者分析的源码是v 5.11.22

链接:msg.c - ipc/msg.c - Linux source code v5.11.22 - Bootlin

do_msgsnd

static long do_msgsnd(int msqid, long mtype, void __user *mtext,size_t msgsz, int msgflg)
{struct msg_queue *msq;struct msg_msg *msg;int err;struct ipc_namespace *ns;DEFINE_WAKE_Q(wake_q);ns = current->nsproxy->ipc_ns;if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)return -EINVAL;if (mtype < 1)return -EINVAL;msg = load_msg(mtext, msgsz);if (IS_ERR(msg))return PTR_ERR(msg);msg->m_type = mtype;msg->m_ts = msgsz;rcu_read_lock();msq = msq_obtain_object_check(ns, msqid);if (IS_ERR(msq)) {err = PTR_ERR(msq);goto out_unlock1;}ipc_lock_object(&msq->q_perm);for (;;) {struct msg_sender s;err = -EACCES;if (ipcperms(ns, &msq->q_perm, S_IWUGO))goto out_unlock0;/* raced with RMID? */if (!ipc_valid_object(&msq->q_perm)) {err = -EIDRM;goto out_unlock0;}err = security_msg_queue_msgsnd(&msq->q_perm, msg, msgflg);if (err)goto out_unlock0;if (msg_fits_inqueue(msq, msgsz))break;/* queue full, wait: */if (msgflg & IPC_NOWAIT) {err = -EAGAIN;goto out_unlock0;}/* enqueue the sender and prepare to block */ss_add(msq, &s, msgsz);if (!ipc_rcu_getref(&msq->q_perm)) {err = -EIDRM;goto out_unlock0;}ipc_unlock_object(&msq->q_perm);rcu_read_unlock();schedule();rcu_read_lock();ipc_lock_object(&msq->q_perm);ipc_rcu_putref(&msq->q_perm, msg_rcu_free);/* raced with RMID? */if (!ipc_valid_object(&msq->q_perm)) {err = -EIDRM;goto out_unlock0;}ss_del(&s);if (signal_pending(current)) {err = -ERESTARTNOHAND;goto out_unlock0;}}ipc_update_pid(&msq->q_lspid, task_tgid(current));msq->q_stime = ktime_get_real_seconds();if (!pipelined_send(msq, msg, &wake_q)) {/* no one is waiting for this message, enqueue it */list_add_tail(&msg->m_list, &msq->q_messages);msq->q_cbytes += msgsz;msq->q_qnum++;atomic_add(msgsz, &ns->msg_bytes);atomic_inc(&ns->msg_hdrs);}err = 0;msg = NULL;out_unlock0:ipc_unlock_object(&msq->q_perm);wake_up_q(&wake_q);
out_unlock1:rcu_read_unlock();if (msg != NULL)free_msg(msg);return err;
}

首先进行判断

if (msgsz > ns->msg_ctlmax || (long) msgsz < 0 || msqid < 0)return -EINVAL;
if (mtype < 1)return -EINVAL;

合法的msqid都是大于等于0的,这个不用管,需要注意的是mtype<1是invalid argument,所以在创建msg_msg时,要确保mtype>=1。

接下来

msg = load_msg(mtext, msgsz);
struct msg_msg *load_msg(const void __user *src, size_t len)
{struct msg_msg *msg;struct msg_msgseg *seg;int err = -EFAULT;size_t alen;msg = alloc_msg(len);if (msg == NULL)return ERR_PTR(-ENOMEM);alen = min(len, DATALEN_MSG);if (copy_from_user(msg + 1, src, alen))goto out_err;for (seg = msg->next; seg != NULL; seg = seg->next) {len -= alen;src = (char __user *)src + alen;alen = min(len, DATALEN_SEG);if (copy_from_user(seg + 1, src, alen))goto out_err;}err = security_msg_msg_alloc(msg);if (err)goto out_err;return msg;out_err:free_msg(msg);return ERR_PTR(err);
}

 

static struct msg_msg *alloc_msg(size_t len)
{struct msg_msg *msg;struct msg_msgseg **pseg;size_t alen;alen = min(len, DATALEN_MSG);msg = kmalloc(sizeof(*msg) + alen, GFP_KERNEL_ACCOUNT);if (msg == NULL)return NULL;msg->next = NULL;msg->security = NULL;len -= alen;pseg = &msg->next;while (len > 0) {struct msg_msgseg *seg;cond_resched();alen = min(len, DATALEN_SEG);seg = kmalloc(sizeof(*seg) + alen, GFP_KERNEL_ACCOUNT);if (seg == NULL)goto out_err;*pseg = seg;seg->next = NULL;pseg = &seg->next;len -= alen;}return msg;out_err:free_msg(msg);return NULL;
}
struct msg_msgseg {struct msg_msgseg *next;/* the next part of the message follows immediately */
};#define DATALEN_MSG	((size_t)PAGE_SIZE-sizeof(struct msg_msg))
#define DATALEN_SEG	((size_t)PAGE_SIZE-sizeof(struct msg_msgseg))

总的来说,就是分配我们传入的bufsz大小的msg_msg,然后将mtext给copy过去,注意,我们这里的msg->security==NULL。

struct msg_msg {struct list_head m_list;long m_type;size_t m_ts;		/* message text size */struct msg_msgseg *next;void *security;/* the actual message follows immediately */
};
struct msg_queue {struct kern_ipc_perm q_perm;time64_t q_stime;		/* last msgsnd time */time64_t q_rtime;		/* last msgrcv time */time64_t q_ctime;		/* last change time */unsigned long q_cbytes;		/* current number of bytes on queue */unsigned long q_qnum;		/* number of messages in queue */unsigned long q_qbytes;		/* max number of bytes on queue */struct pid *q_lspid;		/* pid of last msgsnd */struct pid *q_lrpid;		/* last receive pid */struct list_head q_messages;struct list_head q_receivers;struct list_head q_senders;
} __randomize_layout;
list_add_tail(&msg->m_list, &msq->q_messages);

具体将msg_msg链入的一部是这个,list_add_tail

static inline void list_add_tail(struct list_head *new, struct list_head *head)
{__list_add(new, head->prev, head);
}
static inline void __list_add(struct list_head *new,struct list_head *prev,struct list_head *next)
{next->prev = new;new->next = next;new->prev = prev;prev->next = new;
}

我们也可以知道msgq中的一些字段的含义

msq->q_cbytes += msgsz;
msq->q_qnum++;

q_cbtytes字段就是这个queue中存储的总字节数

q_qnum就是拥有的msg_msg的数量。

从kernel pwn的角度来说,能用的就是load_msg那里,先用alloc_msg构建好msg_msg,所有next指针都分配好了,然后再copy,可以用userfault卡在copy_from_user,然后修改next指针实现地址任意写。

接下来我们分析msg_read 

msg_read

很多细节前面的msgrcv分析copy都讲了,这里主要讲不一样的。

static inline int convert_mode(long *msgtyp, int msgflg)
{if (msgflg & MSG_COPY)return SEARCH_NUMBER;/**  find message of correct type.*  msgtyp = 0 => get first.*  msgtyp > 0 => get first message of matching type.*  msgtyp < 0 => get message with least type must be < abs(msgtype).*/if (*msgtyp == 0)return SEARCH_ANY;if (*msgtyp < 0) {if (*msgtyp == LONG_MIN) /* -LONG_MIN is undefined */*msgtyp = LONG_MAX;else*msgtyp = -*msgtyp;return SEARCH_LESSEQUAL;}if (msgflg & MSG_EXCEPT)return SEARCH_NOTEQUAL;return SEARCH_EQUAL;
}

我们的msgtpy是0,所以mode就是SEARCH_EQUAL

static struct msg_msg *find_msg(struct msg_queue *msq, long *msgtyp, int mode)
{struct msg_msg *msg, *found = NULL;long count = 0;list_for_each_entry(msg, &msq->q_messages, m_list) {if (testmsg(msg, *msgtyp, mode) &&!security_msg_queue_msgrcv(&msq->q_perm, msg, current,*msgtyp, mode)) {if (mode == SEARCH_LESSEQUAL && msg->m_type != 1) {*msgtyp = msg->m_type - 1;found = msg;} else if (mode == SEARCH_NUMBER) {if (*msgtyp == count)return msg;} elsereturn msg;count++;}}return found ?: ERR_PTR(-EAGAIN);
}
static int testmsg(struct msg_msg *msg, long type, int mode)
{switch (mode) {case SEARCH_ANY:case SEARCH_NUMBER:return 1;case SEARCH_LESSEQUAL:if (msg->m_type <= type)return 1;break;case SEARCH_EQUAL:if (msg->m_type == type)return 1;break;case SEARCH_NOTEQUAL:if (msg->m_type != type)return 1;break;}return 0;
}

可以看到,最后会找到与我们传入的type相等的msg_msg

if ((bufsz < msg->m_ts) && !(msgflg & MSG_NOERROR)) {msg = ERR_PTR(-E2BIG);goto out_unlock0;}

我们传入的msgflg是0,所以后面是真,也就是说,如果我们传入的bufsz<msg->m_ts,是没用的,所以我们传入的bufsz必须大于或等于msg->m_ts。

接下来会进入这个函数。

list_del(&msg->m_list);
static inline void list_del(struct list_head *entry)
{__list_del_entry(entry);entry->next = LIST_POISON1;entry->prev = LIST_POISON2;
}
static inline void __list_del_entry(struct list_head *entry)
{if (!__list_del_entry_valid(entry))return;__list_del(entry->prev, entry->next);
}
static inline void __list_del(struct list_head * prev, struct list_head * next)
{next->prev = prev;WRITE_ONCE(prev->next, next);
}
static inline bool __list_del_entry_valid(struct list_head *entry)
{return true;
}

其实就是脱链操作,从kernel pwn的角度,_list_del_entry_valid是直接返回true,这意味着,在这个版本,我们只需随意把这两个指针覆盖为有效可写地址就行了,或许可以构造unlink攻击?

话说其他版本会不会在此增加一些验证??? 

其他和前篇的msgrcv相似,就不说了。

相关文章:

kernel源码分析 do_msgsnd read_msg

笔者分析的源码是v 5.11.22 链接&#xff1a;msg.c - ipc/msg.c - Linux source code v5.11.22 - Bootlin do_msgsnd static long do_msgsnd(int msqid, long mtype, void __user *mtext,size_t msgsz, int msgflg) {struct msg_queue *msq;struct msg_msg *msg;int err;str…...

掌握 CTE 技巧,实现连续日期和月份的 SQL 报表统计

在 SQL 查询中&#xff0c;报表统计往往涉及到特定时间段内的数据汇总&#xff0c;如每日、每月的销售数据等。然而&#xff0c;面对缺少数据的日期或月份&#xff0c;传统 SQL 查询可能会直接跳过这些日期&#xff0c;使得输出的报表在视觉上并不连续。本文将展示如何利用 CTE…...

【表格解决问题】EXCEL行数过多,WPS如何按逐行分别打印多个纸张中

1 问题描述 如图&#xff1a;我的表格行数太多了。打印在一张纸上有点不太好看 2 解决方式 Step01&#xff1a;先选中你需要打印的部分&#xff0c;找到【页面】->【打印区域】->【设置打印区域】 Step02&#xff1a;先选中一行&#xff0c;找到【插入分页符】 Step0…...

Maven讲解从基础到高级配置与实践

一、基础认知 1.1 Maven 的主要作用 Maven 主要是用来管理 Java 项目构建流程的工具&#xff0c;包括以下几个方面&#xff1a; 依赖管理&#xff1a;通过 POM.xml 文件管理项目的外部依赖库&#xff0c;不同版本的依赖包可以通过 Maven 中央仓库自动下载&#xff0c;减少了…...

Vue3组件式父子传值

下面是使用 <script setup> 语法的 Vue 3 组件之间传值的示例。 示例 1:使用 Props 和 Emits 父组件 <template><div><h1>父组件</h1><ChildComponent :message="parentMessage" @reply="handleReply" /><p>…...

网页自动化测试和爬虫:Selenium库入门与进阶

网页自动化测试和爬虫&#xff1a;Selenium库入门与进阶 在现代Web开发和数据分析中&#xff0c;自动化测试和数据采集成为了开发流程中的重要部分。Python 的 Selenium 库是一种强大的工具&#xff0c;不仅用于网页自动化测试&#xff0c;也在网页爬虫中得到了广泛的应用。本…...

Cells 单元

Goto Data Grid 数据网格 Cells 单元 Content Alignment 内容对齐 显示数值的数据网格单元格会将其内容向右对齐。显示其他类型数据的单元格将其内容向左排列。若要更改单元格内容对齐方式&#xff0c;请处理 ColumnView.RowCellDefaultAlignment 事件。 Selection Modes 选…...

2024/11/2 安卓创建首页界面

‌Gradle 8.7 bin‌是指Gradle 8.7版本的二进制包&#xff0c;通常以.zip或.tar.gz格式提供。这个二进制包包含了运行Gradle所需的所有文件&#xff0c;用户可以直接下载并解压使用&#xff0c;无需从源代码编译。 首先了解最常用的布局 线性布局&#xff08;从上到下&#x…...

SpringSession源码分析

默认对常规Session的理解和使用&#xff0c;如何使用Set-Cookie。 Maven库 常见的spring-session-data-redis依赖spring-session-core <dependency><groupId>org.springframework.session</groupId><artifactId>spring-session-core</artifactId&…...

IIC

IIC 目录 IIC BH1750型号的光照传感器 IIC通信协议 iic物理层 IIC软件层协议 -- 那么一主多从&#xff0c;怎么选中与指定的从机通信呢&#xff1f; 从机设备地址 -- 从手册中查看 IIC 写操作 IIC 读操作 硬件IIC和模拟 IIC 使用 模拟 IIC 使用 &#xff01;&…...

LLM Observability: Azure OpenAI (一)

作者&#xff1a;来自 Elastic Vinay Chandrasekhar•Andres Rodriguez 我们很高兴地宣布 Azure OpenAI 集成现已全面上市&#xff0c;它提供了对 Azure OpenAI 服务性能和使用的全面可观察性&#xff01;另请参阅本博客的第 2 部分 虽然我们已经提供了对 LLM 环境的可视性一段…...

qt QBrush详解

1、概述 QBrush是Qt框架中的一个基本图形对象类&#xff0c;它主要用于定义图形的填充模式。QBrush可以用于填充如矩形、椭圆形、多边形等形状&#xff0c;也可以用于绘制背景等。通过QBrush&#xff0c;可以设置填充的颜色、样式&#xff08;如实心、渐变、纹理等&#xff09…...

Excel函数CUnique连接合并指定区域的唯一值

上一篇文章向大家介绍了如何使用VBA在低版本Excel中创建unique函数的方法&#xff0c;今天我跟大家分享一下如何使用函数连接指定区域的唯一值&#xff0c;也就是将unique函数获取的唯一值连接合并成一个&#xff0c;并指定连接符。 同样&#xff0c;我们需要先创建一个自定义的…...

机械革命屏幕设置为RGB

机械革命屏幕设置为RGB 如何设为机械革命屏幕显示为RGB如何设置1.win菜单下输入“显卡控制中心”2.选择显示器3.设置为RGB4.饱和度大家设为自己舒服的就行5.调整亮度 参考来源 如何设为机械革命屏幕显示为RGB 之前买的显示器&#xff0c;感觉调成sRGB看起来非常舒服。就想着是…...

开源项目-投票管理系统

哈喽,大家好,今天主要给大家带来一个开源项目-投票管理系统 投票管理系统主要有首页,发起投票,管理投票,参与投票,查看投票等功能 首页 为用户提供了一键导航到各个功能模块的便捷途径。 新增投票 用户可以在此轻松创建新的投票活动,设置投票主题、选项等信息。 管理…...

LeetCode 104.二叉树的最大深度

题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 示例 2&#xff1a; 输入&#xff1a;root [1…...

Android启动流程_Init阶段

前言 本文将会介绍 Android 启动流程&#xff0c;将基于 Android 10 代码逻辑介绍原生启动过程。 bootloader 上电 -> 加载 recovery 镜像或者 boot 镜像 -> linux kernel 启动 -> 加载 init 进程 -> 加载 zygote 进程 -> systemserver 进程 -> 系统启动 …...

萤火虫算法优化BILSTM神经网络多输入回归分析

目录 LSTM的基本定义 LSTM实现的步骤 BILSTM神经网络 代码 结果分析 展望 完整代码下载:的MATALB代码(代码完整,数据齐全)资源-CSDN文库 https://download.csdn.net/download/abc991835105/88755564 背影 bp神经网络是一种成熟的神经网络,应用非常广,本文用萤火虫算法…...

在线QP(QuotedPrintable)编码解码工具

具体前往&#xff1a;Quoted-printable在线编码解码工具-将给定文本编码为:可打印字符引用编码(简称&#xff1a;QP编码)&#xff0c;也支持在线解码...

【已解决】cra 配置路径别名 @ 后,出现 ts 报错:找不到模块“@/App”或其相应的类型声明。ts(2307)

cra 配置路径别名 后&#xff0c;出现 ts 报错&#xff1a;找不到模块“/App”或其相应的类型声明。ts(2307) 然后可以在 tsconfig.json 中配置 baseUrl 和 paths &#xff1a; {"compilerOptions": {"target": "es5","lib": [&quo…...

从 API Key 管理与审计日志功能看 Taotoken 的企业级安全支持

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 从 API Key 管理与审计日志功能看 Taotoken 的企业级安全支持 对于将大模型能力集成到业务流程中的企业而言&#xff0c;API 访问的…...

阶段与关口:项目管理中的核心触发器与决策机制解析

1. 从“触发器”说起&#xff1a;为什么我们需要阶段与关口&#xff1f;在汽车电子、软件开发乃至任何复杂的项目管理中&#xff0c;我们常常听到“触发器”这个词。它就像一个开关&#xff0c;一个信号&#xff0c;标志着某个条件已经满足&#xff0c;可以启动下一系列动作。今…...

Synopsys工具filter命令:从数据筛选到高效IC设计的实战指南

1. 项目概述&#xff1a;从“大海捞针”到“精准定位”的思维转变在IC设计领域&#xff0c;Synopsys的工具链是我们日常工作中不可或缺的伙伴。无论是DC、ICC2、PT还是VCS&#xff0c;我们每天都要与海量的数据、复杂的网表和成千上万的命令打交道。很多时候&#xff0c;我们面…...

崩坏星穹铁道终极自动化指南:三月七小助手完整使用教程

崩坏星穹铁道终极自动化指南&#xff1a;三月七小助手完整使用教程 【免费下载链接】March7thAssistant 崩坏&#xff1a;星穹铁道全自动 三月七小助手 项目地址: https://gitcode.com/gh_mirrors/ma/March7thAssistant 还在为《崩坏&#xff1a;星穹铁道》中繁琐的日常…...

RK3568开发板TFTP网络启动:告别烧录,实现内核与设备树秒级更新

1. 项目概述与核心价值作为一名在嵌入式领域摸爬滚打了十来年的老鸟&#xff0c;我深知在项目开发的中后期&#xff0c;那种反复修改、编译、烧录、测试的循环有多磨人。尤其是当你需要频繁调整设备树&#xff08;Device Tree&#xff09;来适配一个新传感器&#xff0c;或者微…...

Golang怎么实现HTTP请求取消_Golang如何用context取消正在进行的HTTP请求【实战】

HTTP客户端默认不取消请求是设计选择&#xff0c;需显式通过context.Context传递取消信号&#xff1b;必须用NewRequestWithContext、禁用Client.Timeout、确保Transport组件响应同一ctx。为什么 http.Client 默认不取消请求&#xff1f;Go 的 http.Client 本身不自动响应外部中…...

前端新玩具:用几行JavaScript在网页上控制你的游戏手柄和绘图板

前端新玩具&#xff1a;用几行JavaScript在网页上控制你的游戏手柄和绘图板 当游戏手柄的震动反馈通过网页触发&#xff0c;当数位板的压感数据实时映射到Canvas画布——这些曾需要原生应用才能实现的交互&#xff0c;如今在浏览器中只需几行JavaScript代码。Web HID API的诞生…...

SFT别急着接RL!你的多模态大模型可能一直在“带伤训练”

PRISM团队 投稿量子位 | 公众号 QbitAISFT之后&#xff0c;直接上强化学习就够了吗&#xff1f;小心&#xff0c;你做的可能不是“训练”&#xff0c;而是“还债”。在多模态大模型&#xff08;MLLM&#xff09;的后训练中&#xff0c;行业内长期遵循着一个看似天经地义的范式&…...

Python异步编程与Discord机器人开发:pincer库实战指南

1. 项目概述与核心价值最近在折腾一个游戏服务器的后端&#xff0c;发现处理实时通信和状态同步这块儿&#xff0c;用传统的HTTP轮询或者WebSocket裸写&#xff0c;代码很快就变得又臭又长&#xff0c;维护起来简直是噩梦。就在我头疼的时候&#xff0c;社区里一个叫pincer的项…...

Cyber Engine Tweaks终极指南:彻底优化你的赛博朋克2077游戏体验

Cyber Engine Tweaks终极指南&#xff1a;彻底优化你的赛博朋克2077游戏体验 【免费下载链接】CyberEngineTweaks Cyberpunk 2077 tweaks, hacks and scripting framework 项目地址: https://gitcode.com/gh_mirrors/cy/CyberEngineTweaks Cyber Engine Tweaks是一款专为…...