在Kernel 中,照理說能存取至 0 ~ 4GB。但是實作層面卻是只能讓我們使用到3GB ~ 4GB

這會導致我們無法使用open(),write()這些在user space下的function。

而這樣的限制,實作在current->addr_limit 中

在Kernel中若真的想要能存取 0 ~ 4GB ,就要利用set_fs()與get_fs()來達成。

因為有這樣的限制存在,所以當我們在Linux撰寫程式碼時,如果也叫用了這些系統呼叫的函式,由於這些函式

(像是open(),write())被限定只能存取0—3GB的記憶體空間,可是因為我們目前是在核心程式碼使用這些系統函式,

所以說我們所配置的記憶體空間會是在3GB—4GB之間,

所以如果沒有把系統函式所能存取的記憶體空間重新設定為0—4GB的話,

那我們在核心使用的系統函式將會發生無法存取3GB以上記憶體空間的錯誤.

所以,我們可以在許多的Linux核心函式中看到以下的程式碼區段

oldfs=get_fs(); 

set_fs(KERNEL_DS); 設定為可以存取 0—4GB,包括Linux核心所屬的記憶體空間 執行核心所提供的系統呼叫

filp->f_op->write(filp,buf,size,&filp->f_pos);   

set_fs(oldfs); 執行完系統呼叫後,重新把記憶體空間設定回0—3GB

只有使用上面的方法,才能在内核中使用open,write等的系统调用。其实这样做的主要原因是open,write的参数在用户空间,在这些系统调用的实现里需要对参数进行检查,就是检查它的参数指针地址是不是用户空间的。

系统调用本来是提供给用户空间的程序访问的,所以,对传递给它的参数(比如上面的buf),它默认会认为来自用户空间,在->write()函数中,为了保护内核空间,一般会用get_fs()得到的值来和USER_DS进行比较,从而防止用户空间程序“蓄意”破坏内核空间。 为了解决这个问题; set_fs(KERNEL_DS)将其能访问的空间限制扩大到KERNEL_DS,这样就可以在内核顺利使用系统调用了!

我们这里以open系统调用为例子,它最终会调用下面所示的函数:

satic

int do_getname(const char __user *filename, char *page) {

int retval;  unsigned long len = PATH_MAX;

if (!segment_eq(get_fs(), KERNEL_DS)) {

if ((unsigned long) filename >= TASK_SIZE)

return -EFAULT;

}

其中就会对char __user *filename这个用户指针进行判断,如果它不是segment_eq(get_fs(), KERNEL_DS)就需要如上面描述的检查它的指针是不是用户空间指针。内核使用系统调用参数肯定是内核空间,为了不让这些系统调用检查参数所以必须设置  set_fs(KERNEL_DS)才能使用该系统调用.

file->f_op->write的流程可能会调用access_ok->__range_ok,而__range_ok会判断访问的buf是否在0~addr_limit之间,如何是就ok,否则invalid,这显然是为用户准备的检查。addr_limit一般设为__PAGE_OFFSET,在内核空间,buf肯定>__PAGE_OFFSET,必须修改addr_limit,这就是set_fs的由来。

ps: 在 x86 linux 系統上 ,
KERNEL_DS 為 0xFFFFFFFF ,
USER_DS 可為 0x2000000 , 0x4000000 or 0x80000000 , 所以 , 很容易知道目前 IP 在哪個 space 上
 
 
所以 linux 提供了 :
get_fs() : 取得 process(thread) 的 limited address ( 即 USER_DS )
get_ds() : 取得 Kernel Space limited address ( KERNEL_DS )
set_fs( KERNEL_DS or USER_DS ) : 設定 task limit addr

最新文章

  1. Spring代理模式及AOP基本术语
  2. java 文件保存到本地
  3. .pop ----remove 删除
  4. android 异步加载框架 原理完全解析
  5. rabbitMQ集群部署以及集群之间同步
  6. .NET/C# 类构造函数中this的用法 (转)
  7. Java线程:线程中断
  8. springboot swagger-ui结合
  9. 基于C++Qt4开发的白鸽局域网聊天器
  10. HTML5——表单美化
  11. tshark CAN协议分析初试
  12. redis异常和注意点
  13. 第二阶段冲刺——six
  14. Java接口多线程并发测试 (一)
  15. Executor(一)ExecutorService 线程池
  16. Oracle彻底卸载
  17. python进程与线程介绍
  18. linux-c 调试 gdb
  19. RabbitMQ(一):Windows下RabbitMQ安装
  20. R语言的输出函数cat,sink,writeLines,write.table

热门文章

  1. Composer 安装 zlib_decode(): data error 错误
  2. 对HTML中P标签的思考
  3. SRS之SrsRtmpConn::service_cycle详解
  4. LeetCode 分类颜色
  5. 三、SpringBoot启动时JDBC报错:You must configure either the server or JDBC driver (via the serverTimezone configuration property)
  6. Docker安装ElasticSearch 版本7.1.1
  7. NavMenu 导航菜单
  8. mongdb aggregate聚合操作
  9. maven 打jar包和war包
  10. php中应用redis