千家信息网

Linux内核怎么判断地址是否位于用户空间

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,这篇文章主要介绍"Linux内核怎么判断地址是否位于用户空间",在日常操作中,相信很多人在Linux内核怎么判断地址是否位于用户空间问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对
千家信息网最后更新 2025年12月02日Linux内核怎么判断地址是否位于用户空间

这篇文章主要介绍"Linux内核怎么判断地址是否位于用户空间",在日常操作中,相信很多人在Linux内核怎么判断地址是否位于用户空间问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Linux内核怎么判断地址是否位于用户空间"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、 问题描述

access_ok函数是什么原理?

问题

二、问题分析

我们在内核空间和用户空间进行数据拷贝的时候必须判断用户空间地址是否合法。主要通过偶函数access_ok来判断。

1. Linux用户空间与内核地址空间

Linux 操作系统和驱动程序运行在内核空间,应用程序运行在用户空间,两者不能简单地使用指针传递数据,因为Linux使用的虚拟内存机制,用户空间的数据可能被换出,当内核空间使用用户空间指针时,对应的数据可能不在内存中。

通常32位Linux内核地址空间划分0~3G为用户空间,3~4G为内核空间。注意这里是32位内核地址空间划分,64位内核地址空间划分是不同的。

  • 进程寻址空间0~4G

  • 进程在用户态只能访问0~3G,只有进入内核态才能访问3G~4G

  • 进程通过系统调用进入内核态

  • 每个进程虚拟空间的3G~4G部分是相同的

  • 进程从用户态进入内核态不会引起CR3的改变但会引起堆栈的改变

2. access_ok详解

原型:

access_ok ( type,addr,size);

功能:

  • access_ok — 检查用户空间指针是否有效 注意,根据体系结构的不同,这个函数可能只是检查指针是否在用户空间范围内,在调用这个函数之后,内存访问函数可能仍然返回 -EFAULT

参数说明:

  • typeType of access: VERIFY_READ or VERIFY_WRITE. 请注意,VERIFY_WRITE是VERIFY_READ的超集——如果写入一个块是安全的,那么从它读取总是安全的。addr要检查的块的开始的用户空间指针size要检查的块的大小

返回值:

  • 此函数检查用户空间中的内存块是否可用。如果可用,则返回真(非0值),否则返回假 (0) 。

2. 源码分析

#define access_ok(type, addr, size) (__range_ok(addr, size) == 0)
/* We use 33-bit arithmetic here... */ #define __range_ok(addr, size) ({ \  unsigned long flag, roksum; \  __chk_user_ptr(addr); \  __asm__("adds %1, %2, %3; sbcccs %1, %1, %0; movcc %0, #0" \   : "=&r" (flag), "=&r" (roksum) \   : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \   : "cc"); \  flag; })
static inline void __chk_user_ptr(const volatile void *p, size_t size) {  assert(p >= __user_addr_min && p + size <= __user_addr_max); }

其中__range_ok详解如下:参数对应:

flag   --------  %0 roksum --------  %1 addr   --------  %2 size   --------  %3

汇编指令详解

adds %1, %2, %3

等价于:

rosum = addr + size

这个操作会影响状态位(目的是影响是进位标志C)。

以下的两个指令都带有条件CC,也就是当C=0的时候才执行;如果上面的加法指令进位了(C=1),则以下的指令都不执行,flag就为初始值current_thread_info()->addr_limit(非0),并返回。如果没有进位(C=0),就执行下面的指令:

sbcccs %1, %1, %0

该指令等价于

rosum = rosum - flag - 1

也就是(addr + size) - (current_thread_info()->addr_limit) - 1,操作影响符号位。.

如果(addr + size) >= (current_thread_info()->addr_limit) - 1,则C=1 如果(addr + size) < (current_thread_info()->addr_limit) - 1,则C=0 当C=0的时候执行以下指令,否则跳过(flag非零)。

movcc %0, #0

等价于

flag = 0,给flag赋值0。

综上所述:__range_ok宏等价于:

如果(addr + size) >= (current_thread_info()->addr_limit) - 1,返回非零值 如果(addr + size) < (current_thread_info()->addr_limit),返回零

而access_ok就是检验将要操作的用户空间的地址范围是否在当前进程的用户地址空间限制中。这个宏的功能很简单,完全可以用C实现,不是必须使用汇编。 由于这两个函数使用频繁,就使用汇编来实现部分功能来增加效率。

3. 使用实例

我们在内核拷贝数据到用户空间或者从用户空间拷贝数据到内核空间,都需要判断用户空间地址是否在用户空间。

static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n) {  if (access_ok(VERIFY_READ, from, n))   n = __copy_from_user(to, from, n);  else /* security hole - plug it */   memset(to, 0, n);  return n; }  static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n) {  if (access_ok(VERIFY_WRITE, to, n))   n = __copy_to_user(to, from, n);  return n; }

到此,关于"Linux内核怎么判断地址是否位于用户空间"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

空间 用户 内核 地址 指令 函数 数据 进程 指针 检查 内存 等价 问题 学习 功能 拷贝 时候 影响 不同 安全 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 宁波公安局网络安全支队 软件开发公司招学徒可靠吗 怀旧服服务器几点开始升级 虹口区常规软件开发定制要求 数据库技术 课程设计报告 ios没有抢红包软件开发 山东直播商城软件开发 高校多台服务器分布式计算的意义 疫情期间网络安全知识工信部提示 能看电子报纸的数据库 人类蛋白激酶数据库 手机应用软件开发流程有哪些呢 网络安全和大数据云计算哪个好 麒麟操作系统服务器版开源吗 软件开发的基础设施内涵 西电南校区网络安全创新研究大楼 遨游软件开发 数据库需求分析采用的方法 海康威视运营管理中心服务器 macOS桌面软件开发 网络安全志愿服务别称 聚力青春守护网络安全总结 数据库技术 课程设计报告 linux 服务器 排行 虹口区企业数据库研发厂家价格 自考计算机网络技术复习 灌云口碑好的网络技术诚信经营 路由器显示远端服务器没有响应 qq消息数据库文件 云龙区品牌软件开发
0