arm64 UAO/PAN 特性对用户空间边界读写的影响(copy_from/to_user)

文章目录

      • 1 UAO/PAN 特性由来
      • 2 硬件PAN的支持
      • 3 UAO 的支持

1 UAO/PAN 特性由来

linux 内核空间与用户空间通过 copy_from/to_user 进行数据拷贝交换,而不是通过简单的 memcpy/strcpy 进行拷贝复制,原因是安全问题(这里不详细展开)。

而对应内核有 __probe_kernel_read/__probe_user_read读取用户空间数据,该类接口在用户空间地址存在问题时内核读取用户空间不会导致内核系统出现问题。

那么 __probe_kernel_read和__probe_user_read 具体区别在哪里呢?通过源码可以看到具体区别只有一处:
__probe_kenel_read中设置 addr_limit 为 set_fs(KERNEL_DS),而 __probe_user_read 中设置 addr_limit 为 set_fs(USER_DS),首先需要说明每个任务的 thread 结构中都有一个
addr_limit 变量,该变量标记了该任务能访问的内核空间代码范围,比如内核线程都为addr_limit == KERNEL_DS 表明可以访问任意内核和用户空间地址,而用户态程序 addr_limit == USER_DS 表明只能访问用户空间地址,不能访问内核空间地址,当然在执行一些特殊操作时可以通过 set_fs(KERNEL_DS) 让用户态程序进入内核后可以访问内核地址空间,不过在访问完后会恢复原来的值,对于 arm64 还会在 set_fs 中会设置 set_thread_flag(TIF_FSCHECK)标记,作用是在返回用户空间时检查 addr_limit 是否恢复为 USER_DS。关于 USER_DS 和 KERNEL_DS 可以看内核中 asm/uaccess.h 中相关定义。

总之在这里两个函数会限制访问的地址空间范围,这里再看看 arm64 对 set_fs 的实现:

static inline void set_fs(mm_segment_t fs)
{current_thread_info()->addr_limit = fs;/** Prevent a mispredicted conditional call to set_fs from forwarding* the wrong address limit to access_ok under speculation.*/spec_bar();/* On user-mode return, check fs is correct */set_thread_flag(TIF_FSCHECK);/** Enable/disable UAO so that copy_to_user() etc can access* kernel memory with the unprivileged instructions.*/if (IS_ENABLED(CONFIG_ARM64_UAO) && fs == KERNEL_DS) --------------------------------------------(1)asm(ALTERNATIVE("nop", SET_PSTATE_UAO(1), ARM64_HAS_UAO));elseasm(ALTERNATIVE("nop", SET_PSTATE_UAO(0), ARM64_HAS_UAO,CONFIG_ARM64_UAO));
}

除了常规设置外,arm64 还多了 UAO 相关arm cpu 特性的设置,这里需要分析相关特性原理及使用:
首先看一下 arm64 页表属性中关于读写权限的描述:
在这里插入图片描述
以及在用户态不具有执行权限下的执行权限描述:
在这里插入图片描述
可以看到无论用户空间拥有什么读写权限,内核都至少拥有相同的权限,比如 AP[2:1] = 01 时,用户态具有读写权限,内核也具有读写权限,AP[2:1] = 11 时,用户态拥有仅读权限,而内核态也拥有仅读权限。
再来时 UXN = 0 时,用户态不具有执行权限时,内核态也至少是拥有相同权限的,(SCTLR_ELx.WXN 在 linux arm64 中为 0)所以比如 PXN = 0 时, AP[2:1] = 11 时,用户态具有仅读不可执行权限,而内核态具有仅读和可执行权限。
综上,看起来一切没有问题,在UXN = 0 的一组配置中,内核的权限总是比用户态拥有更多权限,并且内核如果访问用户空间使用封装的 copy_{from/to}_user,get_user/put_user … 等变体访问用户空间,即便发生异常,也可以通过 __ex_table 表来返回 EFAULT,防止内核错误。但是实际情况是:只要 user 非特权可以访问的内存地址,kernel 特权级都有相等或是更高的访问权限。恶意的/有问题的应用可能传入一个落在 kernel 空间的 buf 地址,从而达到破坏 kernel 数据,获取 kernel 数据以及执行用户空间代码的目的。
因此早期内核就提供了接口仔细检查这些地址是否是用户空间地址代码,比如 access_ok(),同时设计了 set_fs 接口可以临时改变传入的地址允许的空间根据 USER_DS 和 KERNEL_DS 来改变,以便其通过 access_ok 的检查。
当 set_fs(KERNEL_DS) 时,addr_limit 允许访问内核和用户空间的所有地址。
当 set_fs(USER_DS) 时,addr_limit 只允许访问用户空间的地址。

access_ok 的实现也很简单,就是通过对应架构实现的 __range_ok 来判断地址范围是否越界。然而即便如此还是有些驱动会有漏洞,或者内核的其他地方不经意的访问到用户空间,从而导致漏洞,有一个例子,这里贴出他们对应的标题,感兴趣的可以自己去研究:

An issue where a provided address with access_ok() is not checked was discovered in i915_gem_execbuffer2_ioctl in drivers/gpu/drm/i915/i915_gem_execbuffer.c in the Linux kernel through 4.19.13

所以为了进一步增强安全,除了这种显式的地址空间检测外,硬件架构上还引入了一系列的硬件访问权限控制来帮助阻挡不经意的或者恶意的访问,就是 PAN 和 UAO 特性。

armv8 上有一类特殊的 load store 指令(sttr*,ldtr*)它们是非特权指令,即在用户态使用的加载和存储指令,以及(str*,ldr*)它们是特权指令在特权模式使用加载和存储指令。

2 硬件PAN的支持

Armv8.1-A引入了硬件Privilege Access Never(PAN)的支持。软件可以设置PSTATE.PAN=1使能这个功能。当这个功能使能时,对于任何具有user可读或可写权限的内存,在CPU运行在特权模式时,对这些内存都不能访问(Access Never,不管内存的特权访问权限是什么)。PAN提供一个硬件控制门,实现运行在kernel态时,任何不小心的(如https://www.cvedetails.com/cve/CVE-2018-20669/  An issue where a provided address with access_ok() is not checked)或故意的对user space memory的访问都会被PAN=1阻止。只有在copy_from/to_user或get/put_user这些预知的地方设置PAN=0,允许对user space内存的访问。
如果启用了 armv8.1 的 PAN 特性,那么str*,ldr* 这些特权指令访问访问用户空间时会产生 data abort 异常,如果禁用 PAN 特性,str*/ldr*则可以正常访问用户空间。因此在
{get/put}user, copy{from/to}_user 的对应架构实现中会暂时禁用 PAN,如下:

ENTRY(__arch_copy_from_user)uaccess_enable_not_uao x3, x4, x5 ----------------------------------------(1)add	end, x0, x2
#include "copy_template.S"uaccess_disable_not_uao x3, x4	  ----------------------------------------(2)mov	x0, #0				// Nothing to copyret
ENDPROC(__arch_copy_from_user)
EXPORT_SYMBOL(__arch_copy_from_user).macro	uaccess_enable_not_uao, tmp1, tmp2, tmp3uaccess_ttbr0_enable \tmp1, \tmp2, \tmp3
alternative_if ARM64_ALT_PAN_NOT_UAOSET_PSTATE_PAN(0) --------------------------------------------------------(3)
alternative_else_nop_endif.endm.macro	uaccess_disable_not_uao, tmp1, tmp2uaccess_ttbr0_disable \tmp1, \tmp2
alternative_if ARM64_ALT_PAN_NOT_UAOSET_PSTATE_PAN(1) --------------------------------------------------------(3)
alternative_else_nop_endif.endm#define SET_PSTATE_PAN(x)		__emit_inst(0xd500401f | PSTATE_PAN | ((!!x) << PSTATE_Imm_shift))

(1)(2)(3)在调用从用户空间拷贝的 api 时首先会调用 uaccess_enable_not_uao 来激活访问用户空间,这里其实调用的就是 SET_PSTATE_PAN(0) (先暂时不看 UAO 特性,假设这里没有启用 UAO 特性),禁用了 PAN ,那么此时使用 ldr/str 指令访问用户空间不会出现问题,当完成访问后调用 SET_PSTATE_PAN(1)再次开启 PAN 特性,所以这里就是在特殊的访问 api 中临时禁用 PAN,以便顺利访问用户空间。

3 UAO 的支持

Armv8.2-a引入了User Access Override (UAO)功能。当软件通过设置PSTATE.UAO=1 使能UAO功能时,sttr*/ldtr* 这些利用非特权权限访问指令会变成正常的Load/store指令(执行在特权级时利用特权级的访问权限,执行在非特权级时利用非特权级的访问权限)。当软件设置PSTATE.UAO=0时,sttr*/ldtr* 这些利用非特权权限访问指令还是使用非特权级访问权限(即使执行在特权级)。什么意思呢?就是当启用了 UAO 后, sttr*/ldtr* 这些指令就具有了特性模式 str*/ldr* 指令相同的行为,一旦访问用户空间就会触发 data abort,而可以正常访问内核空间。
所以当支持 UAO 时,上面的 uaccess_ttbr0_enable 和 uaccess_ttbr0_disable将变为空操作(此时 PAN 为默认启用状态)。而在 copy_xx_user.S 的源码中定义了如下宏:

	.macro ldrb1 ptr, regB, valuao_user_alternative 9998f, ldrb, ldtrb, \ptr, \regB, \val.endm.macro strb1 ptr, regB, valstrb \ptr, [\regB], \val.endm
...
....macro uao_user_alternative l, inst, alt_inst, reg, addr, post_incalternative_if_not ARM64_HAS_UAO
8888:			\inst	\reg, [\addr], \post_inc;nop;alternative_else\alt_inst	\reg, [\addr];add		\addr, \addr, \post_inc;alternative_endif_asm_extable	8888b,\l;.endm

也就是说当支持 UAO 时,加载指令使用的 ldtr*,不支持 UAO 时使用的是 ldr*(PAN 生效)。
所以此时的加载存储指令是非特权指令,当我们在 set_fs 中设置为 KERNEL_DS 时,UAO 生效,非特权指令行为和特权指令一样,因此我们可以正常访问内核空间,但是一旦访问用户空间将会触发 data abort 异常,在 pagefault 流程中我们会进入 __do_kernel_fault -> fixup_exception 从而返回 EFAULT。而当我们 set_fs 为 USER_DS 后会清除 UAO,那么此时使用 ldtr 可以正常访问用户空间,但是不能访问内核空间,可以有效的控制意外的非法空间访问,又可以正确的读取用户空间。
综上,当使用了 PAN 和 UAO 特性后可以弥补 arm64 对用户空间读写访问上的设计缺陷,并且提供更全面的保护机制。所以看起来 PAN 和 UAO 更像是一种对架构的补丁。
通过上述分析,我们可以知道为什么我们在 bcc 中使用 bpf_probe_read_kernel 无法读取到 filename 的真实数据,以及需要切换为 bpf_probe_read_user 的原因。

备注:linux-5.11 后又去掉了 CONFIG_ARM64_UAO 选项,原因是后续 uaccess 不考虑通过 set_fs 来改变 addr_limit。
相关 patch 可以参考:

[11/13] arm64: uaccess: remove set_fs()
[PATCH v5 09/10] ARM: uaccess: remove set_fs() implementation

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

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

相关文章

初始化数组方法大全

初始化数组方法大全 大家好&#xff0c;我是免费搭建查券返利机器人赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;让我们一同深入研究在编程中常用的操作之一——数组的初始化。数组是许多编程语…

pytest --collectonly 收集测试案例

pytest --collectonly 是一条命令行指令&#xff0c;用于在运行 pytest 测试时仅收集测试项而不执行它们。它会显示出所有可用的测试项列表&#xff0c;包括测试模块、测试类和测试函数&#xff0c;但不会执行任何实际的测试代码。 这个命令对于查看项目中的测试结构和确保所有…

C++的基础语句

C前奏 1.变量的定义2.键入和输出3.运算符4.sizeof()函数5.判断6.goto语句7.总结 这个专题&#xff0c;我会用简单的语言介绍C的语法&#xff0c;并会适当的对比实现相同或相似功能的C与python代码写法上的不同。 1.变量的定义 对于python来说&#xff0c;我们可以跳过定义直接…

定岗定编设计:企业职能部门定岗定编设计项目成功案例

一、客户背景及现状分析 某大型车辆公司隶属于某央企集团&#xff0c;建于20世纪60年代&#xff0c;是中国高速、重载、专用铁路车辆生产经营的优势企业&#xff0c;轨道车辆制动机研发制造的主导企业&#xff0c;是隶属于国内最大的轨道交通设备制造上市企业的骨干二级公司。公…

AI绘图软件,科技之旅绘画

科技与艺术的碰撞总能产生令人惊叹的火花&#xff0c;现在小编要给大家介绍一款引领未来艺术潮流的AI绘图软件——首助编辑高手。这是一款将人工智能与创意绘画完美结合的软件&#xff0c;它将为你打开一扇全新的创意之门。 所需工具&#xff1a; 一个【首助编辑高手】软件 …

Qt第一个UI程序设计

在第一个Qt程序的基础上我对ui界面进行设计&#xff0c;点击设计按钮 然后 拖动Label按钮输入想要输入的语句。 运行结果如下图。

通过用户输入数字,并计算二次方程

通过用户输入数字&#xff0c;并计算二次方程 以下实例为通过用户输入数字&#xff0c;并计算二次方程&#xff1a; 实例(Python 3.0) # Filename : test.py # author by : www.dida100.com# 二次方程式 ax**2 bx c 0 # a、b、c 用户提供&#xff0c;为实数&#xff0c;a…

案例1—综合项目组网(2)

交换机连接服务器&#xff1a; 服务器虚拟化&#xff1a; 1. 为什么要用虚拟化技术 2. 虚拟化和NFV的区别 3. 将8台服务器虚拟化为一个资源池的大致步骤 4. 服务器规划情况&#xff1a;管理网和业务网 交换机连接服务器&#xff1a; 1&#xff09;将交换机和服务器相连&am…

算法巡练day03Leetcode203移除链表元素707设计链表206反转链表

今日学习的文章视频链接 https://www.bilibili.com/video/BV1nB4y1i7eL/?vd_source8272bd48fee17396a4a1746c256ab0ae https://programmercarl.com/0707.%E8%AE%BE%E8%AE%A1%E9%93%BE%E8%A1%A8.html#%E7%AE%97%E6%B3%95%E5%85%AC%E5%BC%80%E8%AF%BE 链表理论基础 见我的博…

计算机组成原理 主存和CPU连接与主存提速方案

文章目录 主存与CPU的连接译码器线选法译码片选法总结 位拓展字拓展字位同时拓展 主存提速方案存储周期双端口RAM多模块存储器单体多字存储器多模块多体并行存储器存储器高位交叉编址低位交叉编址 主存与CPU的连接 #mermaid-svg-3wv6WzRP2BvKEHQZ {font-family:"trebuchet…

【线上问题】两台服务器的时间不一致导致jwt解析错误

目录 一、问题描述二、解决方法 一、问题描述 1.线上生产问题&#xff0c;本地和测试环境均无问题 2.本地和测试由于网关和登录服务均在同一台机器 3.线上的登录服务和网关部署不在一起&#xff0c;登录服务的时间正常&#xff0c;网关服务的服务器时间比实际快5秒 4.登录服务j…

负缓存 (在 DNS 中较为常见)

摘要 负缓存&#xff0c;也被称为负值缓存或负面缓存&#xff0c;指的是在域名系统&#xff08;DNS&#xff09;中记录和重用之前失败查询结果的机制。当DNS服务器无法解析一个域名时&#xff0c;它会返回一个特定错误码&#xff08;例如NXDOMAIN&#xff09;&#xff0c;指示…

ChatGPT付费创作系统V2.6.2独立版 +WEB端+ H5端 + 小程序端

详情介绍 安装测试环境:Nginx 1.20+PHP7.4+MySQL 5.7 演示网址已升级至2.6.2最新版,仅供研究测试 WEB端:https://chat.ttbobo.cn 体验后台:https://chat.ttbobo.cn/admin 账号:admin 密码:123456 ChatGPT付费创作系统V2.6.2独立版 +WEB端+ H5端 + 小程序端 - 百创…

鸿蒙原生应用再添新丁!中国移动 入局鸿蒙

鸿蒙原生应用再添新丁&#xff01;中国移动 入局鸿蒙 来自 HarmonyOS 微博1月2日消息&#xff0c;#中国移动APP启动鸿蒙原生应用开发#&#xff0c;拥有超3亿用户的中国移动APP宣布&#xff0c;正式基于HarmonyOS NEXT启动#鸿蒙原生应用#及元服务开发。#HarmonyOS#系统的分布式…

【Linux】进程控制深度了解

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;熟练掌握Linux下的进程控制 > 毒鸡汤&#xff…

【Leetcode】466. 统计重复个数

文章目录 题目思路代码 题目 466. 统计重复个数 思路 题目要求找出一个最大整数 m&#xff0c;使得经过 n2 个字符串 s2 组成的字符串能够被经过 n1 个字符串 s1 组成的字符串完全包含的次数。使用动态规划来记录每个位置匹配的情况&#xff0c;并通过循环节的分析来计算最…

JavaBean

学习目的与要求 熟练掌握<jsp:useBean>、<jsp:setProperty>、<jsp:getProperty>等JSP的操作指令。 本章主要内容 编写JavaBean在JSP中使用JavaBean 一个JSP页面通过使用HTML标记为用户显示数据&#xff08;静态部分&#xff09;&#xff0c;页面中变量的…

利用码云(Gitee)与IDEA轻松管理远程代码库的完整指南

目录 前言1 码云简介2 码云上创建远程库3 IDEA集成码云的步骤3.1 安装Gitee插件并建立连接3.2 项目分享到码云3.3 拉取代码 4 码云复制Github4.1 迁移github项目到码云4.2 代码同步 结语 前言 在软件开发领域&#xff0c;代码托管平台是开发者不可或缺的利器。Github作为全球最…

Qt实现文本编辑器(二)

上一章节讲述了如何制作文本编辑页面&#xff0c;以及应该有哪些功能需要实现&#xff0c;只是做了展示效果&#xff0c;实际的点击事件并没有处理。今天来具体讲解下是如何实现菜单栏以及工具栏上对应的需求吧~ 功能实现 功能&#xff1a; 1、动作消息触发 2、具体功能&am…

客户投诉处理常用的ChatGPT通用提示词模板

客户投诉接收&#xff1a;如何接收客户的投诉&#xff0c;并确保信息的准确记录&#xff1f; 投诉分类与优先级排序&#xff1a;如何对投诉进行分类&#xff0c;并确定处理的优先级&#xff1f; 调查与核实&#xff1a;如何对投诉进行调查和核实&#xff0c;了解问题的真实情…