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

发布时间:2021-07-14 11:52:09 作者:chen
来源:亿速云 阅读:249

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

一、 问题描述

access_ok函数是什么原理?

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

问题

二、问题分析

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

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

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

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

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

2. access_ok详解

原型:

access_ok ( type,addr,size);

功能:

参数说明:

返回值:

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

推荐阅读:
  1. 怎么判断IP地址与掩码是否合法
  2. java判断IP地址是否合法的方法

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

linux

上一篇:Hibernate Session的delete()方法怎么用

下一篇:JSF文件在web.xml中启动异常如何解决

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》