set_fs get_fs

本文介绍在Linux内核编程中如何通过系统调用进行文件操作,包括使用filp_open和filp_close函数打开和关闭文件,以及利用set_fs和get_fs确保地址空间的有效性和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

其实内核里面也可以用系统调用的,直接用read/write是可以的。但要注意几个问题:
一个是要记得编译的时候加上-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中声明。

来源:http://blog.youkuaiyun.com/wzws45/article/details/6063668

-------------------------------------------------------------------------------------------------------------------------------

在linux内核编程时,进行系统调用(如文件操作)时如果要访问用户空间的参数,可以用set_fs,get_ds等函数实现访问。get_ds获得kernel的内存访问地址范围(IA32是4GB),set_fs是设置当前的地址访问限制值,get_fs是取得当前的地址访问限制值。进程由用户态进入核态,linux进程的task_struct结构中的成员addr_limit也应该由0xBFFFFFFF变为0xFFFFFFFF(addr_limit规定了进程有用户态核内核态情况下的虚拟地址空间访问范围,在用户态,addr_limit成员值是0xBFFFFFFF也就是有3GB的虚拟内存空间,在核心态,是0xFFFFFFFF,范围扩展了1GB)。使用这三个函数是为了安全性。为了保证用户态的地址所指向空间有效,函数会做一些检查工作。
如果set_fs(KERNEL_DS),函数将跳过这些检查。
下面是典型用法:

//#define __NO_VERSION__
//#define __KERNEL__
//#define MODULE
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>;
#include <linux/init.h>;
#include <linux/module.h>;
#include <linux/kernel.h>;
#include <linux/file.h>;
#include <linux/fs.h>;
#include <linux/sched.h>;
#include <asm/uaccess.h>;
#include <asm/processor.h>;


int init_module(void)
{
         struct file *fp = NULL;
         char buf[100];
         int i;

         for(i=0;i<100;i++)
                 buf[i] = 0;
         printk(KERN_ALERT "Hello ,ftyjl.\n");
         fp = filp_open("/tmp/8899", 3, 0);   //内核的open函数,返回struct file *
         if (fp == NULL)
                 printk(KERN_ALERT "filp_open error ,ftyjl.\n");
         mm_segment_t old_fs=get_fs(); //下面两步,设置当前执行环境为kernel_ds,否则会出错
         set_fs(get_ds());
         fp->f_op->read(fp, buf, 2, &fp->f_pos);   //调用真正的read
         set_fs(old_fs);   //恢复环境
         printk(KERN_ALERT "ftyjl:read[%s]\n", buf);

         printk(KERN_ALERT "end of Hello ,ftyjl.\n");
         return 0;
}
void cleanup_module(void)
{
         printk(KERN_ALERT "Good bye, ftyjl\n");
}

MODULE_LICENSE("Proprietary");

来源:http://blog.youkuaiyun.com/zjc0888/article/details/7266730

<think>好的,我需要帮助用户理解这段Linux内核模块中的代码。首先,我应该分步骤分析每个函数的作用和它们之间的关系。 首先,用户提到了old_fs = get_fs();。这里,get_fs()函数用于获取当前进程的文件系统访问模式。内核中,进程描述符有一个地址限制,决定可以访问的用户空间还是内核空间。用户可能需要知道get_fs()属于asm/uaccess.h,返回的是addr_limit的值。 接下来是set_fs(KERNEL_DS);。KERNEL_DS是一个宏,代表内核空间的地址空间。这里设置文件系统访问模式为内核空间,允许后续操作绕过用户空间的检查,直接访问内核地址。需要说明,这个操作有风险,可能引发安全问题,所以要谨慎使用。 然后是pfile = filp_open(image_name, O_RDWR | O_CREAT | O_EXCL, 0755);。filp_open()类似于用户空间的open(),用于在内核中打开或创建文件。参数O_RDWR是读写,O_CREAT表示不存在则创建,O_EXCL确保文件是新建的。第三个参数0755是文件权限。需要注意的是,image_name应该是内核空间的路径,比如使用绝对路径,并且确保路径有效。 最后set_fs(old_fs);恢复原来的地址限制,避免影响后续操作。这部分很重要,因为不恢复的话可能导致其他部分的内核代码出现意外行为。 用户可能需要了解这段代码的上下文,通常在内核模块中需要操作文件时会用到。但需要强调,直接操作文件系统在内核中并不常见,可能带来稳定性和安全问题,应该优先考虑用户空间的方法。 另外,要提醒用户这些函数的使用需要包含正确的头文件,比如linux/fs.h和asm/uaccess.h。同时,错误处理也很重要,比如检查filp_open()返回的IS_ERR(pfile)。 可能用户是在编写内核模块时需要创建或打开文件,但必须警告他们这种方式的风险,并建议仅在必要时使用,确保恢复原设置。可能还需要提及替代方案,比如通过系统调用让用户空间处理文件操作。</think>这段代码是Linux内核模块中用于操作文件的典型模式,涉及内核态下的文件系统访问。让我们逐步分析其作用和实现原理: 1. `old_fs = get_fs();` - 作用:保存当前进程的文件系统访问模式 - 原理:`get_fs()`来自`<asm/uaccess.h>`,获取当前线程的`addr_limit`(地址空间限制) - 注意:内核默认使用`USER_DS`(用户空间地址),限制内核代码直接访问用户空间指针 2. `set_fs(KERNEL_DS);` - 作用:临时扩大地址空间限制 - 原理:`KERNEL_DS`表示内核空间地址范围(0xFFFFFFFF),允许访问内核地址 - 风险:此时若操作用户空间指针可能导致内核崩溃,必须确保路径参数是内核空间地址 3. `filp_open(image_name, ...)` - 作用:内核态文件操作接口 - 参数解析: - `O_RDWR | O_CREAT | O_EXCL`:读写模式+创建新文件+排他性创建 - `0755`:文件权限(所有者rwx,组和其他rx) - 注意:路径`image_name`必须是内核空间地址(如通过`kmalloc`分配) 4. `set_fs(old_fs);` - 作用:恢复原始地址限制 - 必要性:防止后续代码因意外使用用户空间指针导致安全问题 典型使用场景: ```c // 创建/sys/kernel/debug下的调试文件 char *path = "/sys/kernel/debug/my_file"; struct file *fp; mm_segment_t old_fs = get_fs(); set_fs(KERNEL_DS); fp = filp_open(path, O_CREAT|O_RDWR, 0644); if (IS_ERR(fp)) { // 错误处理 } // 文件操作... // filp_write()/filp_read() filp_close(fp, NULL); set_fs(old_fs); ``` 注意事项: 1. 必须成对使用`set_fs()`,确保异常路径也能恢复原状态 2. 文件路径需使用绝对路径,相对路径可能指向不可预测的位置 3. 建议优先考虑用户空间文件操作,仅在必要时使用内核文件接口 4. 内核5.6+版本对`filp_open()`的使用有更严格限制 替代方案建议: 对于大多数需求,更安全的做法是: 1. 通过`sysfs`或`debugfs`创建虚拟文件 2. 使用`procfs`接口 3. 通过netlink与用户空间进程通信 该模式常见于: - 内核调试日志记录 - 硬件固件加载 - 特殊驱动需要直接访问文件系统 - 内核自检机制 请特别注意:在内核中直接操作文件系统属于高风险行为,可能导致安全漏洞或系统不稳定,应严格限制使用场景并做好错误处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值