Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to manipulate a file in the linux kernel

2025-03-01 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/01 Report--

This article will explain in detail how to manipulate a file in the linux kernel. The editor thinks it is very practical, so I share it for you as a reference. I hope you can get something after reading this article.

I. description of the problem

How do I manipulate a file in the kernel?

2. Operation function

1. Analysis.

In user mode, reading and writing files can be done through read and write system calls (C library functions are actually encapsulation of system calls). However, there are no such system calls in the kernel state, so how can we read and write files?

Reading the Linux kernel source code, you can see that what is trapped in the kernel is actually executing the two functions sys_read and sys_write, but these two functions are not exported using EXPORT_SYMBOL, which means that other modules cannot be used.

The specific implementation of system call in fs/open.c is as follows (kernel version 3.14):

SYSCALL_DEFINE3 (open, const char _ user *, filename, int, flags, umode_t, mode) {if (force_o_largefile ()) flags | = Olympique; return do_sys_open (AT_FDCWD, filename, flags, mode);}

Trace the do_sys_open () function

Long do_sys_open (int dfd, const char _ user * filename, int flags, umode_t mode) {struct open_flags op; int fd = build_open_flags (flags, mode, & op); struct filename * tmp; if (fd) return fd; tmp = getname (filename); if (IS_ERR (tmp)) return PTR_ERR (tmp); fd = get_unused_fd_flags (flags) If (fd > = 0) {struct file * f = do_filp_open (dfd, tmp, & op); if (IS_ERR (f)) {put_unused_fd (fd); fd = PTR_ERR (f);} else {fsnotify_open (f); fd_install (fd, f);}} putname (tmp); return fd;}

You will find that it mainly uses the do_filp_open () function, which is in fs/namei.c.

Struct file * do_filp_open (int dfd, struct filename * pathname, const struct open_flags * op) {struct nameidata nd; int flags = op- > lookup_flags; struct file * filp; filp = path_openat (dfd, pathname, & nd, op, flags | LOOKUP_RCU); if (unlikely (filp = = ERR_PTR (- ECHILD)) filp = path_openat (dfd, pathname, & nd, op, flags) If (unlikely (filp = = ERR_PTR (- ESTALE)) filp = path_openat (dfd, pathname, & nd, op, flags | LOOKUP_REVAL); return filp;}

This function finally opens the file and returns a pointer of type file. So we just need to find other places where the do_filp_open () function is called to find the file manipulation function we need.

In the file fs/open.c, the filp_open function also calls the file_open_name function.

/ * * filp_open-open file and return file pointer * * @ filename: path to open * @ flags: open flags as per the open (2) second argument * @ mode: mode for the new file if O_CREAT is set, else ignored * * This is the helper to open a file from kernelspace if you really * have to. But in generally you should not do this, so please move * along, nothing to see here.. * / struct file * filp_open (const char * filename, int flags, umode_t mode) {struct filename name = {. Name = filename}; return file_open_name (& name, flags, mode);} EXPORT_SYMBOL (filp_open)

The function file_open_name calls do_filp_open, and the interface is very similar to the sys_open function, and the call parameters are the same as sys_open, and exported using EXPORT_SYMBOL, so you can use this function to open files in the kernel, which is very similar to open in the application layer.

/ * * file_open_name-open file and return file pointer * * @ name: struct filename containing path to open * @ flags: open flags as per the open (2) second argument * @ mode: mode for the new file if O_CREAT is set, else ignored * * This is the helper to open a file from kernelspace if you really * have to. But in generally you should not do this, so please move * along, nothing to see here.. * / struct file * file_open_name (struct filename * name, int flags, umode_t mode) {struct open_flags op; int err = build_open_flags (flags, mode, & op); return err? ERR_PTR (err): do_filp_open (AT_FDCWD, name, & op);}

two。 All operation functions

Using the same method, a set of functions that manipulate files in the kernel are found, as follows:

The parameters of these functions are very similar to the application layer file IO functions, open, read, write, close.

3. User space address

Although we have found these functions, we cannot use them directly.

Because in the vfs_read and vfs_write functions, the parameter buf points to the memory address of the user space, if we use the kernel space pointer directly, we will return-EFALUT.

This is because the buffer used exceeds the address range of user space. General system calls will require you to use a buffer that cannot be in the kernel area. This can be solved with set_fs () and get_fs ().

In include/asm/uaccess.h, there are the following definitions:

# 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))

If used, it can be performed in the following order:

Mm_segment_t fs = get_fs (); set_fs (KERNEL_FS); / / vfs_write (); / / vfs_read (); set_fs (fs)

System call is originally provided to the user space of the program access, so, the parameters passed to it (such as the above buf), it will default to think from user space, in the read or write () function, in order to protect the kernel space, generally use the value obtained by get_fs () to compare with USER_DS, so as to prevent user space procedures from "intentionally" destroying the kernel space.

Now to use the system call in kernel space, the parameter address passed to read or write () is the address of kernel space. Above USER_DS (USER_DS ~ KERNEL_DS), if you don't do any other processing, in the write () function, you will think that the address is beyond the scope of USER_DS, so it will be considered as "sabotage" in user space, so no further execution is allowed.

To solve this problem, set_fs (KERNEL_DS) extends the space limit it can access to KERNEL_DS so that system calls can be used smoothly in the kernel!

With the support of VFS, user-mode processes can use read and write system calls to read and write any type of file system, but how can we manipulate files without such system calls in the linux kernel?

We know that read and write actually execute sys_read and sys_write after entering the kernel state, but look at the kernel source code and find that none of the functions that manipulate the files are exported (using EXPORT_SYMBOL export), that is, they cannot be used in the kernel module, so what should I do?

By looking at the source code of sys_open, we found that it mainly uses the do_filp_open () function, which is in fs/namei.c, while in the change file, the filp_open function is also an indirect call to the do_filp_open function, and the interface and sys_open function are very similar, with the same call parameters as sys_open, and exported using EXPORT_SYMBOL, so we guess that the function can open the file with the same function as open.

III. Examples

Makefile

Ifneq ($(KERNELRELEASE),) obj-m:=sysopen.o else KDIR: = / lib/modules/$ (shell uname-r) / build PWD: = $(shell pwd) all: $(info "1st") make-C $(KDIR) make $(PWD) modules clean: rm-f * .ko * .o * .mod.o * .symvers * .cmd * .mod.c * .order endif

Sysopen.c

# include # include MODULE_LICENSE ("GPL"); MODULE_AUTHOR ("yikoulinux"); void test (void) {struct file * file = NULL; mm_segment_t old_fs; loff_t pos; char buf [64] = "yikoulinux"; printk ("test ()"); file = filp_open ("/ home/peng/open/test.txt\ n", O_RDWR | O_APPEND | Olympiad creation 0644) If (IS_ERR (file)) {return;} old_fs = get_fs (); set_fs (KERNEL_DS); pos = 0; vfs_write (file,buf,sizeof (buf), & pos); pos = 0; vfs_read (file,buf,sizeof (buf), & pos); printk ("buf:%s\ n", buf); filp_close (file,NULL); set_fs (old_fs); return } static int hello_init (void) {printk ("hello_init\ n"); test (); return 0;} static void hello_exit (void) {printk ("hello_exit\ n"); return;} module_init (hello_init); module_exit (hello_exit)

Compile:

Install the module:

View the files for the operation:

View the contents of the file:

It can be seen that the file was manipulated successfully in the kernel module.

This is the end of this article on "how to operate a file in the linux kernel". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, please share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report