IT猫扑网:您身边最放心的安全下载站! 最新更新| 软件分类| 专题汇总| 手机版

您当前所在位置:IT猫扑网 > 操作系统 > LINUX > 在linux内核中操作文件的方法

在linux内核中操作文件的方法

时间:2015-06-28 00:00 来源:IT猫扑网|http://www.itmop.com/ 作者:网管联盟 我要评论(0)

  #include <linux/kernel.h>

  #include <linux/module.h>

  #include <linux/init.h>

  #include <linux/fs.h>

  #include <linux/string.h>

  #include <linux/mm.h>

  #include <linux/syscalls.h>

  #include <asm/unistd.h>

  #include <asm/uaccess.h>

  #define MY_FILE &/root/LogFile&

  char buf[128];

  struct file *file = NULL;

  static int __init init(void)

  {

  mm_segment_t old_fs;

  printk(&Hello, I'm the module that intends to write messages to file.n&);

  if(file == NULL)

  file = filp_open(MY_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);

  if (IS_ERR(file)) {

  printk(&error occured while opening file %s, exiting...n&, MY_FILE);

  return 0;

  }

  sprintf(buf,&%s&, &The Messages.&);

  old_fs = get_fs();

  set_fs(KERNEL_DS);

  file->f_op->write(file, (char *)buf, sizeof(buf), &file->f_pos);

  set_fs(old_fs);

  return 0;

  }

  static void __exit fini(void)

  {

  if(file != NULL)

  filp_close(file, NULL);

  }

  module_init(init);

  module_exit(fini);

  MODULE_LICENSE(&GPL&);

  其中:

  typedef struct {

  unsigned long seg;

  } mm_segment_t;

  #define KERNEL_DS    MAKE_MM_SEG(0xFFFFFFFFUL)

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

  基本思想:

  一个是要记得编译的时候加上-D__KERNEL_SYSCALLS__

  另外源文件里面要#include   <linux/unistd.h>

  如果报错,很可能是因为使用的缓冲区超过了用户空间的地址范围。一般系统调用会要求你使用的缓冲区不能在内核区。这个可以用set_fs()、get_fs()来解决。在读写文件前先得到当前fs:

  mm_segment_t   old_fs=get_fs();

  并设置当前fs为内核fs:set_fs(KERNEL_DS);

  在读写文件后再恢复原先fs:   set_fs(old_fs);

  set_fs()、get_fs()等相关宏在文件include/asm/uaccess.h中定义。

  个人感觉这个办法比较简单。

  另外就是用flip_open函数打开文件,得到struct file *的指针fp。使用指针fp进行相应操作,如读文件可以用fp->f_ops->read。最后用filp_close()函数关闭文件。 filp_open()、filp_close()函数在fs/open.c定义,在include/linux/fs.h中声明。

  解释一点:

  系统调用本来是提供给用户空间的程序访问的,所以,对传递给它的参数(比如上面的buf),它默认会认为来自用户空间,在->write()函数中,为了保护内核空间,一般会用get_fs()得到的值来和USER_DS进行比较,从而防止用户空间程序&蓄意&破坏内核空间;

  而现在要在内核空间使用系统调用,此时传递给->write()的参数地址就是内核空间的地址了,在USER_DS之上(USER_DS ~ KERNEL_DS),如果不做任何其它处理,在write()函数中,会认为该地址超过了USER_DS范围,所以会认为是用户空间的&蓄意破坏&,从而不允许进一步的执行; 为了解决这个问题; set_fs(KERNEL_DS);将其能访问的空间限制扩大到KERNEL_DS,这样就可以在内核顺利使用系统调用了!

  补充:

  我看了一下源码,在include/asm/uaccess.h中,有如下定义:

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

  #define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF)

  #define USER_DS MAKE_MM_SEG(PAGE_OFFSET)

  #define get_ds() (KERNEL_DS)

  #define get_fs() (current->addr_limit)

  #define set_fs(x) (current->addr_limit = (x))

  而它的注释也很清楚:

  /*

  * The fs value determines whether argument validity checking should be

  * performed or not. If get_fs() == USER_DS, checking is performed, with

  * get_fs() == KERNEL_DS, checking is bypassed.

  *

  * For historical reasons, these macros are grossly misnamed.

  */

  因此可以看到,fs的值是作为是否进行参数检查的标志。系统调用的参数要求必须来自用户空间,所以,当在内核中使用系统调用的时候,set_fs(get_ds())改变了用户空间的限制,即扩大了用户空间范围,因此即可使用在内核中的参数了。

关键词标签:linux内核

相关阅读 安装红帽子RedHat Linux9.0操作系统教程 Tomcat9.0如何安装_Tomcat9.0环境变量配置方法 多种操作系统NTP客户端配置 Linux操作系统修改IP Linux实现SCSI硬盘热插拔及在线识别 Linux下用CDMA modem拨号上网

文章评论
发表评论

热门文章 安装红帽子RedHat Linux9.0操作系统教程 安装红帽子RedHat Linux9.0操作系统教程 Linux服务器:设计高性能网站架构-LLMP Linux服务器:设计高性能网站架构-LLMP 使用Clonezilla迁移到虚拟Linux环境 使用Clonezilla迁移到虚拟Linux环境 Linux上的MRTG流量监控中心 Linux上的MRTG流量监控中心 Linux 双网卡绑定一个IP原理及实现 Linux 双网卡绑定一个IP原理及实现 linux和windows等系统远程控制ubuntu桌面 linux和windows等系统远程控制ubuntu桌面

相关下载

人气排行 Linux下获取CPUID、硬盘序列号与MAC地址 dmidecode命令查看内存型号 linux tc实现ip流量限制 安装红帽子RedHat Linux9.0操作系统教程 linux下解压rar文件 lcx.exe、nc.exe、sc.exe入侵中的使用方法 Ubuntu linux 关机、重启、注销 命令 查看linux服务器硬盘IO读写负载 linux命令行浏览器的使用方法 Linux NFS服务固定端口及防火墙配置 U盘安装Ubuntu 10.04 Linux清除用户登录记录和命令历史方法