享未来数码网
首页 > 彩电 > 反复探究工控SCADA技术中的accessok函数内幕解析

反复探究工控SCADA技术中的accessok函数内幕解析

一、问题探究

access_ok函数背后的工作原理是什么?

问题

二、分析解析

在进行内核空间与用户空间之间的数据拷贝操作时,我们需要确保用户空间地址的合法性。主要是通过access_ok函数来实现这一检查。

Linux用户空间与内核地址区隔

Linux操作系统及其驱动程序运行于内核空间,而应用程序则运行于用户空间,两者不能直接通过指针进行数据交换,因为Linux采用虚拟内存机制,使得用户空间的数据可能会被交换出内存,当内核试图使用用户指针时,对应的数据可能不再存在于物理内存中。

通常情况下,32位Linux系统将其4GB虚拟地址空間划分为0-3GB作为用户区域和3-4GB作为核心区域。值得注意的是,这里的讨论基于32位环境,64位环境下的划分方式有所不同。

进程寻址范围从0到4G

进程在用户态只能访问0-3G区域,而只有进入核心态才能访问3-4G区域

每个进程共享同样的虚拟地址空間中的3-4G部分(即相同的核心区)

当进程从用户态转入核心态时,它不会改变CR3寄存器,但会改变堆栈。

access_ok深入解读

原型:

access_ok (type, addr, size);

功能:

access_ok - 检查指定类型是否可以对指定大小范围内的 用户模式指针进行读取或写入。

参数说明:

type 访问类型:VERIFY_READ 或 VERIFY_WRITE 注意,VERIFY_WRITE 是 VERIFY_READ 的超集 —— 如果一个块可以安全地被写入,那么它也必然能够安全地被读取。addr 要检查的块开始位置在 用户模式下的指针size 需要检查大小

返回值:

该函数用于验证位于 用户模式 中的一个 内存块 是否可用。如果可用,则返回真(非零),否则返回假(零)。

源码细节分析 #define access_ok(type, addr, size) (_range_ok(addr, size) != 0)

我们使用33-bit算术。在这个宏中,我们首先调用了_range_ok宏,然后将其结果与零比较。如果_result 为非零,则表明_user_ptr_check成功,并且_access_ok也成功,因此整个表达式为非零;如果_result 为 零,则表示_range_check失败,所以整个表达式也是 零。

define _range_ok(addr, size) ({ \ unsigned long flag; \

_range_check_user_ptr(addr);

_asmlinkage long __user *_chk_user_ptr(const volatile void *p, size_t size) { assert(p >= _user_addr_min && p + size <= _user_addr_max); }

static inline void _chk_user_ptr(const volatile void p, size_t s) { assert(p >= _user_addr_min && p + s <= _user_addr_max); }

flag = 1; / 假设flag初始值为1 */ \

_roksum = addr + size; \

asm("adds %1,%2,%3;setcc %0,%1" : "=r" (flag), "+r" (_roksum), "Ir" (addr), "0" (current_thread_info()->addr_limit)); \

flag; })

其中_range-ok详解如下:参数对应:

flag —— 未初始化变量 —— %{[}01]

roksum —— 计算出的总和 —— %{[}01]

addr —— 指定的起始位置 —— %{[}01]

.size — 指定的长度 — %{[}01]

汇编代码详解:

adds %{[\]01},{[\]02},{[\]03}

等价于:

roksum = addr + length;

这个操作影响状态标志C。

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

sbcccs %{[\]01},{[\]01},{\[00}

这条指令等效于:

roksum = roksum - flag - 1;

也就是 (addr+length) - (``current_thread_info()->addr_limit``) - 1, 操作符号位。

如果 (addr+length) >= (current_thread_info()->addr_limit) - 1, 则 C=1 如果 (addr+length) < ( ``current_thread_info()->addr_limit `` ), 则 C=0 当 C==O 时 执行以下命令否则跳过(Flag 非 零)

最后一条命令:

movcc %{[}{]}%{{{\}}%{%{}%}, {%{}%

等效于:

Flag = O;

给 Flag 赋予初级值 O.

综上所述: _range-ok' 宏 等效于: 如果 (add+len)>=(curthread->addresslimit)-l', 返回非O 值,如果`(add+len)<(curthread->addresslimit)', 返回O 值

而 'Access-ok' 就是验证将要操作 的User-space 地址范围是否在当前 进程 的User-address-limit 范围之中。这两个 函数由于频繁使用,就通过汇编 来实现一些功能以增加效率。

三、实例应用

在拷贝数据到User-space或者从User-space 拷贝到Kernel-space 时,都需要判断 User-space 地址是否合法。

静态 inline 不透明长整数类型 mustcheck_copy_from_user(void *to , const void *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 , O,n);

return n;

}

静态 inline 不透明长整数类型 mustcheck_copy_to_user(void user to , const void to, unsigned long n){

if(access_ok(VERIFY_WRITE,to,n))

n = copy_to_ouser(to,*from,n);

return n;

}

以上便是关于 Linux 系统中的 Access-ok 函数的一些基本介绍及相关源码分析。

标签:

猜你喜欢

电视机专卖店 小型食品微波杀...
了解微波杀菌机的基本原理 微波杀菌机是利用高频微波对食品进行加热和杀菌。它通过产生强烈的磁场来引起水分在食品中的分子运动,从而达到加热和消毒的目的。这种方...
国产电视销量排行榜前十名 地外生命探测器...
地外生命探测器:gea分离机背后的未知 引言 在浩瀚的宇宙中,人类总是充满了对未知的好奇和探索欲。自从卡普拉星系发现有可能存在液态水以来,科学家们就开始寻...
收音机 如何选择适合家...
在当前的健康意识日益提高的时代,家庭卫生已经成为我们生活中不可或缺的一部分。为了确保家中的空气和表面保持清洁,消除细菌和病毒,我们需要考虑到各种不同的杀菌...
电视机怎么选 中国资源卫星应...
中国资源卫星应用中心招聘:开启天地智慧之门 招聘背景与意义 中国资源卫星应用中心招聘,旨在吸引具有先进技术和创新思维的专业人才,为国家空间探索和资源利用提...

强力推荐