get_fs()和set_fs()解析

在内核中使用有些系统调用(如打开,写文件等操作)需要使用get_fs,set_fs对他们进行保护。如:oldfs=get_fs();   

set_fs(KERNEL_DS);   

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

set_fs(oldfs);

        只有使用上面的方法,才能在内核中使用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的由来。

 

  1. #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })



  2. /* addr_limit is the maximum accessible address for the task. we misuse

  3. * the KERNEL_DS and USER_DS values to both assign and compare the

  4. * addr_limit values through the equally misnamed get/set_fs macros.

  5. * (see above)

  6. */



  7. #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)

  8. #define USER_DS MAKE_MM_SEG(TASK_SIZE)



  9. #define get_ds() (KERNEL_DS)

  10. #define get_fs() (current_thread_info()->addr_limit)

  11. #define set_fs(x) (current_thread_info()->addr_limit = (x))



  12. #define segment_eq(a,b) ((a).seg == (b).seg)

 

  1. /* how to get the thread information struct from C */

  2. static inline struct thread_info *current_thread_info(void)

  3. {

  4.        struct thread_info *ti;

  5.        __asm__("and.d $sp,%0; ":"=r" (ti) : "0" (~8191UL));

  6.        return ti;

  7. }

 

  1. struct thread_info {

  2.        struct task_struct *task; /* main task structure */

  3.        struct exec_domain *exec_domain;/* execution domain */

  4.        unsigned long flags; /* thread_info flags (see TIF_*) */

  5.        mm_segment_t addr_limit; /* user-level address space limit */

  6.        __u32 cpu; /* current CPU */

  7.        int preempt_count; /* 0=premptable, <0=BUG; will also serve as bh-counter */

  8.        struct restart_block restart_block;

  9. };

 

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
class Monitoring_point { private: QString JCD_Name;//监测点名称 QString JCD_Type;//监测点所检测的数据类型 QString JCD_Number;//监测点编号 public: Monitoring_sensor *sensor;//监测点有传感器 void set_JCD_Name(QString n); void set_JCD_Type(QString t); void set_JCD_Number(QString n); QString get_JCD_Name(); QString get_JCD_Type(); QString get_JCD_Number(); }; class Monitoring_sensor { private: QString CGQ_Number;//传感器编号 QString CGQ_State;//传感器状态 QString CGQ_Manufacturer;//生产商 QString CGQ_Outnumber;//出厂号 public: void set_CGQ_Number(QString n); QString get_CGQ_Number(); void set_CGQ_State(QString s); QString get_CGQ_State(); void set_CGQ_Manufacturer(QString m); QString get_CGQ_Manufacturer(); void set_CGQ_Outnumber(QString o); QString get_CGQ_Outnumber(); }; class Data { private: double FS;//风速 double FX;//风向 double SSF;//伸缩缝 double WD;//温度 double SD;//湿度 double ZZWY;//支座位移 public: Monitoring_point *Point;//监测数据中有监测点,到时候选择某一监测点进行数据展示 Time *times;//监测数据中有检测的时间 void setFS(double fs); void setFX(double fx); double getFS(); double getFX(); void setSSF(double s); double getSSF(); void setWD(double w); double getWD(); void setSD(double s); double getSD(); void setZZWY(double z); double getZZWY(); Data d; d.Point=new Monitoring_point();//分配内存给Point指针 d.Point->sensor=new Monitoring_sensor();//分配内存给sensor指针 d.Point->sensor->set_CGQ_Number(CGQ_Number_1);为什么报错 error: invalid use of incomplete type 'class Monitoring_sensor' 怎么修改
最新发布
07-12

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值