linux How to operate files in kernel -- use get_fs() and set_fs(KERNEL_DS)
包含内核头文件、
包括模块相关代码,
加载初始化态配置,
引入fs目录下的功能,
处理字符串操作所需的库,
涉及内存管理的组件,
引用syscalls表实现系统调用,
使用asm utilities函数表和接口表完成开发。
#defineMY_FILE"/root/LogFile"
charbuf[128];
structfile*file=NULL;
static int__init __stdcall init(void)
{
mm_segment_t old_fs = 0;
The module that aims to write messages to files is printing a message "Hello, I'm the module that aims to write messages to file.".
if ((file == NULL))
{
file = fopen(MY_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);
}
if (IS_ERR(file)) {
printk("error occurred while opening file %s, exiting...", MY_FILE);
return 0;
}
return 0;
sprintf(buf,"%s","The Messages.");
old_fs = get_fs();
将文件系统状态设置为 KERNEL_DS;
将数据块从缓冲区中写入指定位置;
恢复到原来的文件系统状态;
return0;
}
staticvoid__exit fini(void)
{
if(file!=NULL)
filp_close(file,NULL);
}
module_init(init);
module_exit(fini);
MODULE_LICENSE("GPL");
among :
typedefstruct{
unsignedlongseg;
}mm_segment_t;
#defineKERNEL_DSMAKE_MM_SEG(0xFFFFFFFFUL)
#defineMAKE_MM_SEG(s)((mm_segment_t){(s)})
Basic Considerations:
Adding the preprocessor directive -D__KERNEL_SYSCALLS__ is essential.
A crucial step involves ensuring that the source file includes the necessary headers by using #include <linux/unistd.h>.
如果报告错误,则可能是因为所使用的缓冲区超出用户空间地址范围。大多数系统调用要求所使用的缓冲区不得处于内核空间中。为此可以使用set_fs()和get_fs()来解决此问题。
获取当前缓冲区并读写文件前需先:
- 获取当前缓冲区并将其设为内核缓冲区:
c
mm_segment_t old_fs = get_current_buffer(); if (oldFs != KERNEL_BUFFER) { set_current_buffer(KERNEL_BUFFER); } - 恢复原缓冲区:
c
if (oldFS != -1) { set_current_buffer(oldFS); }
需要注意的是set...\*()等函数需通过相关宏实现,请参考文件include/asm/uaccess.h中的相关内容定义。
I personally find this approach to be quite straightforward.
The other approach is to utilize the flip_open() function to open a file, obtain a struct file pointer pointing to fp. Once the pointer is obtained, it can be used to perform corresponding operations such as reading documents by executing fp->f_ops->read(). Finally, the flip_close() function should be called to close the file. The flip_open() and flip_close() functions are defined in fs/open.c, and their implementation details can be found in include/linux/fs.h.
系统集成呼叫 originally 为用户空间中的程序访问提供了基础支持。因此,在调用该功能时(例如传递的参数如buf),默认情况下它会从用户空间获取数据,并通过write函数进行处理。为了保护内核空间的安全性,默认情况下它会从用户空间获取数据,并通过write函数进行处理。通常通过get_fs()函数来获取用户态资源的总和,并与USER_DS进行对比。为了防止用户空间程序故意破坏内核安全性的操作,请确保相关机制的有效运行。
Now, you must utilize system calls within kernel space. Accessing ->write(), whose argument is derived from the kernel segment assigned to USER_DS (USER_DS ~ KERNEL_DS). Unless you take additional steps, attempting to write beyond USER_DS range will be classified as a malicious operation. This implies that addresses beyond the USER_DS range are treated as user-space operations. Consequently, no further execution is permitted. To resolve this issue, allocate more memory for system calls within the kernel by invoking set_fs(KERNEL_DS). This action expands the memory region reserved for system calls within the kernel DS segment. As a result, system calls can operate seamlessly within the kernel.
我仔细阅读了源代码文件include/asm/uaccess.h,并注意到其中包含以下一些定义:
首先是一个宏函数MAKE_MM_SEG(s),其功能是创建一个MM_SEGMENT类型的变量s;
接着定义了KERNEL_DS为全息位掩码值为0xFFFFFFFF的MM_SEGMENT实例;
然后定义USER_DS为当前页框偏移量PAGE_OFFSET的MM_SEGMENT实例;
此外还有两个函数get_ds()返回KERNEL_DS值,
以及set_fs(x),用于将地址限制设置为x。
And its notes are clear
From what I understand, fs represents a marker indicating whether parameters are being checked. The prerequisites for system calls must originate from user-space resources,
therefore, whenever utilizing system calls within the kernel environment, setting up get\_ds alters or modifies,
by expanding the allocated user space budget allows access to necessary parameters within,
