X86 SMAP(Supervisor Mode Access Prevention)机制引入的一个问题分析

news2024/12/22 19:02:02

在Linux系统中,当涉及到用户态和内核态数据拷贝的时候,如果不考虑建立kernel space和user space的共享映射实现的零拷贝情况,一般是调用copy_from_user/copy_to_user/put_user/get_user几组宏来实现的。在早些时候,对于用户态指针非法(没有VMA)或者缺页(有VMA但是MMU没有映射)两种情况,在函数实现中使用修复表进行处理,前一种情况下会返回错误码,第二种情况则通过page fault流程建立物理PFN映射,之后在进入修复表流程完成剩下的操作。而对于合法的用户态指针,则直接在内核中访问即可。所以,从内核中可以直接访问当前进程的用户空间,所使用的虚拟地址也与当前进程处于用户空间时的地址完全相同。反之则不允许。

但是这个结论似乎在运行最新linux的 x86 平台上遇到了反例,即便在内核中访问合法的用户态地址,也会被禁止,做个实验:

在设备驱动中直接读取用户态传递下来的buf指针的内容:

运行用户态用例,发现测试进程被KILL,内核报告permission违例。

分析现场,发现出错地址0x7ffc922277b0和内核report的fault地址是一致的,并且,此虚拟地址对应的四级页表都有映射(PGD 23144d067 P4D 23144d067 PUD 2315d8067 PMD 23b0e9067 PTE, P4D和PGD重合)。也就是说,被访问的虚拟地址既不是非法地址,也不缺页,按照本文开头的分析,这个地址应该能够被内核安全访问才对,但是这里却报了错。

仔细分析出错LOG,发现出错原因是#PF: error_code(0x0001) - permissions violation,许可违例。

原因分析:

出现这个问题的原因和硬件架构和内核版本都有关系,最根本的原因是CPU硬引入了一个新的功能引起的,在最新的X86处理器的CR4寄存器中,引入了SMEP和SMAP 控制BIT,用来配置内核对用户态地址空间的访问权限。SMAP(Supervisor Mode Access Prevention)是Intel从Haswell微架构开始引入的一种新特征,它在CR4寄存器上引入一个新标志位SMAP,如果这个标志为1,内核访问用户进程的地址空间时就会触发一个页错误,目的是为了防止内核因为自身错误意外访问用户空间,这样就可以避免一些内核漏洞所导致的安全问题.但是由于内核在有些时候仍然需要访问用户空间,因此intel提供了两条指令STAC和CLAC用于临时打开/关闭这个功能,反复使用STAC和CLAC会带来一些轻微的性能损失,但考虑到增加的安全性,还是建议开启.

SMEP:位于Cr4的第20位,作用是让处于内核权限的CPU无法执行用户代码。
SMAP:位于Cr4的第21位,作用是让处于内核权限的CPU无法读写用户代码。

可以通过如下命令查看CPU是否支持smap功能,如下图所示,我的8核处理器每个核心都支持SMAP。

$ sudo cpuid|grep -i smap

而内核中有配置选项CONFIG_X86_SMAP用来启用或者关闭SMAP功能,默认情况下是打开的,所以才会遇到这个问题。

那么为什么copy_from_user/put_user宏又可以访问用户态指针呢?

以get_user为例,其它宏定义实现类似,在get_user的核心实现__get_user_1中,在进行真正的用户态指针访问前后,程序调用了ASM_STAC/ASM_CLAC去打开/关闭内核访问用户地址空间权限的功能:

并且在标号1处的修正表实现中也调用了CLAC指令对SMAP功能进行了控制,所以get_user才能安全地访问用户地址空间。

内核还提供了两个函数,用来供驱动开发者设置安全访问用户空间的代码区域,分别是#define user_access_begin和user_access_end。

用这两个调用保护访问用户内存的区域,重新测试:

发现程序正常执行,没有被KILL,说明这两个接口起到了作用。

作为对比,尝试关闭SMAP,重新编译内核,确认是否可以在内核中直接访问用户态地址:

测试发现,在关闭SMAP机制后,在内核模块中可以直接访问用户态的地址了:


总结:

所以,内核直接访问用户态指针导致报告page fault错误的原因是直接访问用户态内存触发了SMAP保护,内核提供了配置和API接口关闭这种保护,而本文开头提到的几个宏定义能够安全将访问用户态内存的原因,也是由于在访问器件,关闭了SMAP保护。

从普遍意义的角度来讲,内核态访问用户态地址空间是没有任何问题的,只是需要注意不同的架构下实现上会有微小差别,至少目前,没有看到其它架构有类似SMAP机制的实现。

参考文章

Supervisor Memory Protection - OSDev Wiki


结束

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

STM32F4X SDIO(一) SD卡介绍

STM32F4X SDIO(一) SD卡介绍 SD卡分类外观分类容量分类传输速度分类 在之前的章节中,讲过有关嵌入式的存储设备,有用I2C驱动的EEPROM、SPI驱动的FLASH和MCU内部的FLASH,这类存储设备的优点是操作简单,但是缺…

同步网盘推荐及挑选指南:便捷、安全、适用的选择

同步网盘是最近热门的文件协同工具之一,因其使用的便捷性受到了诸多用户的青睐。如今网盘市场产品众多,有什么好用的同步网盘?如何挑选同步网盘?是许多需求者关心的问题。 如何挑选同步网盘?在同步网盘挑选过程中要从…

GZ035 5G组网与运维赛题第4套

2023年全国职业院校技能大赛 GZ035 5G组网与运维赛项(高职组) 赛题第4套 一、竞赛须知 1.竞赛内容分布 竞赛模块1--5G公共网络规划部署与开通(35分) 子任务1:5G公共网络部署与调试(15分) 子…

详解Jmeter中的BeanShell脚本

BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法,所以它和java是可以无缝衔接的,学了Java的一些基本语法后,就可以来在Jmeter中写写BeanShell脚本了 在利用jmeter进行接口测试或者性能测试的时候&#xff0c…

Vue--》简易资金管理系统后台项目实战(前端)

今天开始使用 vue3 + ts + node 搭建一个简易资金管理系统的前后端分离项目,因为前后端分离所以会分两个专栏分别讲解前端与后端的实现,后端项目文章讲解可参考:后端链接,我会在前后端的两类专栏的最后一篇文章中会将项目代码开源到我的github上,大家可以自行去进行下载运…

C++多态(超级详细版)

目录 一、什么是多态 二、多态的定义及实现 1.多态构成条件 2.虚函数的重写和协变 虚函数重写的两个例外: 2.1协变 2.2析构函数的重写 (析构函数名统一处理成destructor) 3.重载、覆盖(重写)、隐藏(重定义)的对比 4.final 和 overr…

在本地模拟C/S,Socket套接字的使用

public class SocketTCP01Server {public static void main(String[] args) throws IOException {/**1.在本机的 9999 端口监听 ,等待连接细节: 要求在本机没有其他服务在监听999细节:这个ServerSocket 可以通过accept()返回多个Socket[多个客…

指针仪表读数YOLOV8NANO

指针仪表读数YOLOV8 NANO 采用YOLOV8 NANO训练,标记,然后判断角度,得出角度,可以通过角度,换算成数据

End-to-End Adversarial-Attention Network for Multi-Modal Clustering

方法 融合表征h f _f f​ ∑ v \sum_v ∑v​w v _v v​ h v h^v hv 辅助信息 作者未提供代码

2558. 从数量最多的堆取走礼物

2558. 从数量最多的堆取走礼物 难度: 简单 来源: 每日一题 2023.10.28 给你一个整数数组 gifts ,表示各堆礼物的数量。每一秒,你需要执行以下操作: 选择礼物数量最多的那一堆。如果不止一堆都符合礼物数量最多,从中选择任一…

Java工具库——Commons IO的50个常用方法

工具库介绍 Commons IO(Apache Commons IO)是一个广泛用于 Java 开发的开源工具库,由Apache软件基金会维护和支持。这个库旨在简化文件和流操作,提供了各种实用工具类和方法,以便更轻松地进行输入输出操作。以下是 Com…

基于51单片机的温度测量报警系统的设计与制作

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、实习目的二、实习任务2.1 设计温度测量报警系统硬件电路2.2 温度测量报警系统软件编程、仿真与调试;2.3 完成温度测量报警系统的实物制作与调试…

【蓝桥每日一题]-前缀和与差分(保姆级教程 篇2)#差分序列

昨天讲的概念和模板,今天讲一个差分序列的好题(好好体会里面的优化思想): 目录 题目: 思路: 题目: 手动打出样例哈 输入: 输出: 4 …

Android问题笔记四十二:signal 11 (SIGSEGV), code 1 (SEGV_MAPERR) 的解决方法

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 👉关于作者 专注于Android/Unity和各种游戏开发技巧,以及各种资源分享&…

etcd的mvcc源码剖析

mvcc简介 悲观锁 在对于一些临界资源进行读写的时候,为了防止其他人进行同步的修改数据,直接将当前的数据锁住,不让别人使用,来实现并发安全 乐观锁 在对临界资源进行操作的时候,不锁住数据,实现独占&…

锐捷NBR 1300G路由器 越权CLI命令执行漏洞

执行查看版本的命令不需要其它权限, 访问url: /WEB_VMS/LEVEL15/构造payload数据包: POST /WEB_VMS/LEVEL15/ HTTP/1.1commandshow version&strurlexec%04&mode%02PRIV_EXEC&signnameRed-Giant.回显如下: 测试发现…

软件测试之单元测试

前言 为什么我们需要测试? 让产品可以快速迭代,同时还能保持高质量 对于一些相对稳定的系统级别页面,自动化测试在提高测试的效率的方面起到非常重要的作用。前端的自动化测试主要包括:浏览器测试和单元测试。Vue官方脚手架自带…

Linux系统之watch命令的基本使用

Linux系统之watch命令的基本使用 一、watch命令介绍二、watch命令的使用帮助2.1 watch命令的help帮助2.2 watch命令的语法解释 三、watch命令的基本使用3.1 使用默认的2秒时间间隔执行ls命令3.2 每隔10秒执行一次ps命令3.3 每隔1秒输出一次磁盘使用情况3.4 高亮显示grep命令的输…

File 复制文件

一.代码 package org.example;import java.io.*;public class day05 {public static void main(String[] args) throws IOException {//复制图片//创建字节输入流管道与源文件接通final FileInputStream is new FileInputStream("D:\\temp\\day05\\图2.jpg");//创建…

软考高项-计算题(2)

题4 项目的总预算是包含管理储备的,所以总预算应该是:13238102*360 ETC(BAC-EV)/CPI BAC60 EV60*0.318 CPI18/200.9 ETC42/0.9 答案选择C A 题5 因为题目中提到了“按目前的状况继续发展”,那么是:ETC(BAC-EV)/CPI EV1230*0…