How to operate User Files in Linux kernel: Use get_fs () and set_fs (kernel_ds) to call the system call to change permissions, and then use the Kernel File Operation Function to access user space.
(1) macro Introduction
The source code is defined in include/ASM/uaccess. h as follows:
#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))
And its annotations are also clear:/** the FS value determines whether argument validity checking shoshould be completed MED or not. If get_fs () = user_ds, checking is already med,
Get_fs () = kernel_ds, checking is bypassed. for historical reasons, these macros are grossly misnamed .*/
Therefore, we can see that the FS value is a flag for checking the parameters. When the system call parameters are required to come from the user space and use the system call in the kernel, set_fs (get_ds () changes the user space limit, that is, expands the user space range, therefore, you can use the parameters in the kernel.
(2) function example: Create a new text in a module and write content to the text.
#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 "LogFile"//#define MY_FILE "/root/LogFile"asmlinkage long sys_open(const char __user *filename,int flags, int mode);char buf[128];struct file *file = NULL; static int __init init(void){ mm_segment_t old_fs; int ret = 0; printk("<0>""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); // file = sys_open(MY_FILE, O_RDWR | O_APPEND | O_CREAT, 0644); if (IS_ERR(file)) { printk("<0>""error occured while opening file %s, exiting.../n", MY_FILE); return 0; } memset(buf,0x61,128); sprintf(buf,"%s", "The Messages is xjkdljflk."); old_fs = get_fs(); printk("<0>""old_fs is %lx/n",old_fs.seg); set_fs(KERNEL_DS); old_fs = get_fs(); printk("<0>""old_fs is %lx/n",old_fs.seg); printk("<0>""KERNEL_DS is %lx/n",KERNEL_DS); ret = file->f_op->write(file, (char *)buf, sizeof(buf), &file->f_pos); if(ret < 0) printk("<0>""file write failed/n"); 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");
The makefile used is as follows:
ifeq ($(KERNELRELEASE),)KERNELDIR := /usr/src/linux-headers-2.6.32-28-genericPWD := $(shell pwd)modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_installclean: rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .PHONY:modules modules_install cleanelseobj-m := call.oendif
After compilation, execute insmod and rmmod to view the desired result.
(3) process description
Use the flip_open function to open the file and obtain the pointer FP of struct file. Use the pointer FP for corresponding operations. For example, you can use FP-> f_ops-> Read to read the file, and finally use the filp_close () function to close the file.
In short: to use the system call in the kernel space, the parameter address passed to-> write () is the address of the kernel space, on user_ds (user_ds ~ Kernel_ds). If no other processing is performed, in the write () function, the address is deemed to have exceeded the user_ds range. Therefore, the address is regarded as a "deliberate destruction" of the user space ", further execution is not allowed. To solve this problem, set_fs (kernel_ds) expands the space limit that can be accessed to kernel_ds, so that the system can be called smoothly in the kernel!