您当前的位置 :环球传媒网>博客 > 正文
环球动态:access_ok函数是什么原理?linux基础命令表一览?
2022-09-14 10:04:33 来源:环球周刊网 编辑:

最近小编看到大家都在讨论linux空间(linux基础命令表)相关的事情,对此呢小编也是非常的感应兴趣,那么这件事究竟是怎么发生的呢?具体又是怎么回事呢?下面就是小编搜索到的关于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. 源码分析

#defineaccess_ok(type,addr,size)(__range_ok(addr,size)==0)

/*Weuse33-bitarithmetichere...*/#define__range_ok(addr,size)({\unsignedlongflag,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;})

staticinlinevoid__chk_user_ptr(constvolatilevoid*p,size_tsize){assert(p>=__user_addr_min&&p+size<=__user_addr_max);}

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

flag--------%0roksum--------%1addr--------%2size--------%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. 使用实例

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

staticinlineunsignedlong__must_checkcopy_from_user(void*to,constvoid__user*from,unsignedlongn){if(access_ok(VERIFY_READ,from,n))n=__copy_from_user(to,from,n);else/*securityhole-plugit*/memset(to,0,n);returnn;}staticinlineunsignedlong__must_checkcopy_to_user(void__user*to,constvoid*from,unsignedlongn){if(access_ok(VERIFY_WRITE,to,n))

关键词: linux空间 linux基础命令表

相关阅读
分享到:
版权和免责申明

凡注有"环球传媒网"或电头为"环球传媒网"的稿件,均为环球传媒网独家版权所有,未经许可不得转载或镜像;授权转载必须注明来源为"环球传媒网",并保留"环球传媒网"的电头。