Transferred from: http://www.ibm.com/developerworks/cn/linux/l-cn-kernelmodules/
To maintain the stability and sustainability of the Linux kernel, the kernel introduces the feature of loadable modules in the development process. A kernel loadable module is a set of code that can be loaded into the kernel while the kernel is running. Typically, we will fail to load the same module on two different cores, even on two adjacent patch level versions. This is because the kernel, while introducing loadable modules, takes version information checks on the module. This is a mechanism that is independent of the module code, but is connected to the kernel. This verification mechanism ensures that the modules loaded by the kernel are user-approved and secure. This article will consider the module version checking mechanism from the perspective of the kernel module publisher, and use and understand the mechanism from the perspective of the developer and the authorized root user.
Kernel loadable Modules Overview
The important feature of Linux in the development process (i.e., after Linux 1.2) is the introduction of modules, which provide a kernel that can be extended at run time. The Loadable module (Loadable Kernel module, or LKM), also known as a module, is a set of target code (not a complete executable program) that can be loaded into the kernel while the kernel is running. This means that you do not need to recompile the kernel when refactoring and using loadable modules. Modules are written and compiled at the location of the code: internal modules and external modules, namely the In-tree module and the Out-of-tree module, the modules written and built outside the kernel tree are external modules. This is wrong under Linux if you just think that the loadable module is an external module or that the module is outside the kernel when it communicates with the kernel. When the module is loaded into the kernel, the Loadable module is already part of the kernel. In addition, the Linux distributions we use have used the necessary modules in the system boot process initrd, unless we only discuss the underlying kernel (base kernel). This paper mainly discusses the external modules of Linux 2.6.
The most significant difference between a loadable module and Linux 2.6 and 2.4 is that the module loading process changes (as shown in Figure 1, the Loadable module in Linux 2.6 completes the connection in the kernel). Some of the other changes are broadly as follows:
- The suffix of the module and the loading tool;
For authorized users using modules, the most intuitive change to the module should be the module suffix changed from the original. o file (that is, object) to a. ko file (that is, kernel object). Also, in Linux 2.6, the module uses a new load-loading toolset Module-init-tools (Tools Insmod and Rmmod are redesigned). The building process of the module changed enormously, and in Linux 2.6 The code was first compiled into an. o file, and the. ko file is generated from the. o file, and the build process generates files such as. mod.c,. MOD.O, and so on.
- The additional process of module information;
In Linux 2.6, the module's information was added at build time, unlike Linux 2.4, where the previous module information was attached when the module was loaded into the kernel (at Linux 2.4, this process was done by the tool Insmod).
- The tag options for the module.
In Linux 2.6, there are some adjustments to the options for the management module, such as canceling the can_unload tag (used to mark the usage state of the module), adding a config_module_unload tag (for labeling The Block unloading), and so on. Some interface functions, such as reference counting for modules, have also been modified.
Figure 1. The module completes the connection in the kernel
Growing to Linux 2.6, more and more features in the kernel are being modularized. This is due to the fact that the Loadable module has a relatively easy-to-maintain, easy-to-debug feature. The Loadable module also saves memory space for the kernel because the module is usually loaded when it is really needed. Depending on the module, loadable modules can also be divided into three main types: device drivers, file systems, and system calls. It should also be noted that although loadable modules are loaded from user space into kernel space, they are not user-space programs.
Back to top of page
Version checking of the module
The rapid development of Linux has resulted in a large difference between the neighboring versions of the kernel, namely, the version patch number (patch level, the fourth digit of the kernel version number) that is adjacent to the kernel. To ensure the stability of the kernel, Linux has adopted a version-checking mechanism for the modules when loading the module into the kernel. The load module shown in Listing 1 fails when the system environment that is expected to load the module is at odds with the building environment of the module.
Listing 1. Load Module failed
# insmod/hello/hello.ko insmod:error inserting './hello/hello.ko ':-1 Invalid module Format # DMESG | grep hell o [9206.599843] hello:disagrees about version of symbol Module_layout
In Listing 1, the environment of the module Hello.ko at the time of the build is inconsistent with the current system, causing the tool insmod to fail when attempting to load the module Hello.ko to the kernel. Hello.ko is a normal module that uses only the function PRINTK (you can find the file hello/hello.c in the sample source code). We command DMESG (or you can view system log files such as/var/log/messages etc., if you enable these system logs) to obtain the specific reason for module mount failure, the module Hello.ko mount failure is due to the module_layout in the module The version information for the exported symbol does not match the current kernel. The function module_layout is defined after the Kernel module version option Modversions (that is, the kernel can load the module's version check option). Listing 2 shows the definition of module_layout in the kernel file kernel/module.c.
Listing 2. function Module_layout
/* kernel/module.c * /#ifdef config_modversions void module_layout (struct module *mod, struct modversion_ Info *ver, struct kernel_param *kp, struct kernel_symbol *ks, struct tracepoint * Const *TP) { }< C11/>export_symbol (module_layout); #endif
Listing 3. Structural Body Modversion_info
/* include/linux/module.h */ struct modversion_info { unsigned long CRC; Char Name[module_name_len]; };
As you can imagine, the second parameter of the function Module_layout ver stores the version checksum information for the module. The CRC (Cyclic redundancy Check, the cyclic redundancy code check) value for the module checksum is saved in the structure Modversion_info (see Listing 3). Linux has two layers of verification for loadable modules: The CRC value checksum of the module and the Vermagic check. The module CRC value check for the module (kernel) export symbols, is a simple ABI (that is, application Binary Interface) consistency check, in Listing 1, the root cause of the module Hello.ko load failure is not through the CRC value check (i.e. module The CRC value of the _layout is not the same as in the current kernel), while the module vermagic (that is, version Magic String) holds the kernel version of the module compile and the configuration information such as SMP (see Listing 4, module Hello.ko vermagic information) , when the module vermagic and the host information does not match, it will also terminate the module loading.
Listing 4. Vermagic Information for modules
# uname–r 2.6.38-10-generic # modinfo./hello/hello.ko FileName: ./hello/hello.ko License: Dual BSD/GPL srcversion: 31fe72da6a560c890ff9b3f depends: vermagic : 2.6.38-9- Generic SMP mod_unload Modversions
Normally, the CRC value of the exported symbol for the kernel and module is saved in the file module.symvers, which needs to be obtained after the kernel configuration option config_modversions is turned on and the kernel is fully compiled (or you can obtain the file after compiling the external module. The CRC information for the exported symbol of the module is saved, and its information is saved in the format shown in Listing 5.
Listing 5. To export the CRC value of a symbol
0X1DE386DD module_layout vmlinux export_symbol <CRC> <Symbol> <module >
The Linux kernel completes the module's CRC value check before the module is loaded, and then checks the character information in the vermagic, Figure 2 shows the process of calling the function that is related to the module version check in the kernel (respectively, in function Setup_load_info and Check_modinfo Check). Linux uses the declaration function attribute in GCC to __attribute__ the version information of the module. The modules that are built have several sections, such as. Modinfo,. Gnu.linkonce.this_module, and __versions, and these ELF subsections (section) preserve the information required for module validation (about these sections For additional information, you can view the file <module>.mod.c and tools Modpost generated when the module was built, as shown in Listing 8 and listing 15).
Figure 2. Two-layer version verification process for modules
To better understand the loadable module, we look at the kernel header file include/linux/module.h, which not only defines the struct modversion_info described above (see Listing 3) but also defines structs such as the struct module. The module CRC value check is the content of the module __versions section, which is the additional struct modversion_info information. The CRC check procedure for the module is done in the function Setup_load_info. Linux uses the. Gnu.linkonce.this_module section to resolve the module's addition to the struct module information. The function check_modinfo in file kernel/module.c completes the comparison of Vermagic values between the host and the module (see Listing 6). The function Get_modinfo in Listing 6 is used to obtain the vermagic information in the kernel, and the module vermagic information is stored in the ELF's. Modinfo section.
Listing 6. function Check_modinfo
/* KERNEL/MODULE.C * /static int check_modinfo (struct module *mod, struct load_info *info) { const char *MODM Agic = Get_modinfo (info, "Vermagic"); ... } else if (!same_magic (Modmagic, Vermagic, info->index.vers)) { ... } ... return 0; }
Kernel Space and user space
The operating system is responsible for the independent operation of the program and protects the resources from unauthorized access, which is implemented in a modern CPU with different operating modes (levels) to be designed. The kernel runs at the highest level of the CPU, the kernel state, also known as Superuser, while the application runs at the lowest level, the user state. In this system, there are two different zones in Linux: Kernel space and user space. The module runs in kernel space, and the application runs in the corresponding user space.
It should be noted that the Vermagic information for the module comes from the macro vermagic_string in the kernel header file include/linux/vermagic.h, where the macro uts_release holds the kernel version information (see Listing 7). The header file associated with include/generated/utsrelease.h needs to be pre-compiled by the kernel, i.e. by command make or make modules_prepare.
Listing 7. Macro Vermagic_string
/* KERNEL/MODULE.C */ static const char vermagic[] = vermagic_string; /* include/linux/vermagic.h */ #define vermagic_string \ uts_release "" \ MODULE_VERMAGIC_SMP Module_vermagic_preempt \ module_vermagic_module_unload module_vermagic_modversions \ MODULE_ Arch_vermagicline
Back to top of page
Loading and unloading of modules
In the above, we used the tool Insmod when loading the module. In Linux 2.6, the tool Insmod was redesigned and used as a program in the Toolset Module-init-tools, which is called Sys_init_module through the system (you can view the header file include/asm-generic/ UNISTD.H) connects the module's version check, module loading and other functions (as shown in Figure 3). Module-init-tools is a modular load-loading toolset designed for the 2.6 kernel that runs in Linux user space and contains programs rmmod for uninstalling modules in the current kernel.
Figure 3. Loading and unloading of modules
Table 1. Some of the programs in the Toolset Module-init-tools
name |
Description |
Insmod |
Loading the module into the currently running kernel |
Rmmod |
Uninstalling the module from the currently running kernel |
Lsmod |
Displays the module information that the current kernel has installed |
Modinfo |
Check the target file associated with the kernel module and print out all the information obtained |
Modprobe |
Automatically load related modules with dependency files created by Depmod |
Depmod |
Create a dependency file for the kernel loadable module, modprobe use it to load the module automatically |
It is worth mentioning that in the Module-init-tools can be used in the module loading and unloading program modprobe. The procedure Modprobe's internal function call procedure is similar to what you want to do with Insmod, except that its loading process will look for some module-loaded configuration files, and modprobe can resolve the dependencies between modules when loading the module, even if necessary, program modprobe Other modules that the module relies on will be loaded automatically when a module is loaded.
Back to top of page
Some other details
Linux also checks user permissions when loading modules from user space into the kernel. The load of the module must be a superuser who obtains cap_sys_module privileges, which is the first thing to check when the module is loaded (see Figure 2). In Linux 2.6, the module generated some temporary files at build time, such as. o files,. mod.o files, and so on. Understanding the generation of these files can help us to better understand the kernel module building process of Linux 2.6 and the checking of version information. File. O is the module code (that is,. c files) compiled after the target file, file. mod.o the corresponding file. Mod.c. File <module>.mod.c is an extension to <modulue>.c, listing 8 shows the contents of the file Kobject-example.mod.c (that is, the module Kobject-example.ko. mod.c file ), you can see three subsections related to module version checking.
Listing 8. File kobject-example.mod.c
# Cat./kobject/kobject-example.mod.c ... Module_info (Vermagic, vermagic_string); struct Module __this_module __attribute__ ((Section (". Gnu.linkonce.this_module")) = { ... }; static const struct Modversion_info ____versions[] __used __attribute__ ((Section ("__versions")) = { ... }; static const char __module_depends[] __used __attribute__ ((Section (". Modinfo")) = "depends="; Module_info (srcversion, "b06f9b8b7ab52aeed247b9f");
Listing 8 shows the three sections in the module Kobject-example.ko as well as the macro Module_info, and the last line srcversion the kernel configuration option Module_srcversion_all to be turned on. By the above, we know that these three sections are the additional information for the module version check. We view the. Modinfo section through the tool Objdump (see Listing 9, the Vermagic information for the module). <module>.ko additional information is merged from file <module>.o to file <MODULE>.MOD.O. The kernel tool Modpost completed this step, and the tool is required for the Linux 2.6 kernel module to be built.
Listing 9. Use the tool objdump to view the. Modinfo section
# objdump--section=.modinfo-s hello/hello.o hello/hello.o: file format elf64-x86-64 Contents of section. Modinfo: 0000 6c696365 6e73653d 4475616c 20425344 license=dual BSD 0010 2f47504c xx /GPL. # modinfo hello/hello.o filename: hello/hello.o License: Dual BSD/GPL # objdump--section=. Modinfo-s hello/hello.mod.o ... # objdump--section=.modinfo-s Hello/hello.ko ...
By the above, we know that the kernel tree top-level Makefile file contains the kernel version of the information, and the information is compiled and added to the module (header file include/generated/utsrelease.h saved kernel version information from the top-level Makefile). In table 1, the tool lsmod opens the file/proc/modules queries the loaded modules in the current kernel (see listing 10), and the file/proc/modules is also used by Rmmod when uninstalling the module. Also, if you do not see the corresponding string output under the terminal after loading the module Hello.ko, you need to check the file/PROC/SYS/KERNEL/PRINTK and reset the message level.
Listing 10. Use of Tool lsmod
# insmod./kobject/kobject-example.ko # ls/sys/kernel/kobject_example/ bar baz foo # Lsmod | grep kobject kobject_example 12857 0 # Cat/proc/modules | grep kobject kobject_example 12857 0- Live 0xffffffffa0523000
When the Linux 2.6 build module, the tool Modpost is called by Scripts/makefile.modpost, generating <module>.mod.c and file Module.symvers (see listing 15). After the kernel option config_modversions is turned on, the file Makefile.build will invoke the tool genksyms (now located in the kernel tree scripts/genksyms directory, when Linux 2.4 is a module toolset modutils section) to generate CRC information (see Listing 11). Where code call Cmd_gensymtypes is the invocation of the tool genksyms. Another clear way is to use the tool objdump or readelf to view the relevant ELF subsections and use Make–n to view the module build process.
Listing 11. Part of the file Makefile.build
Ifndef config_modversions Cmd_cc_o_c = $ (CC) $ (c_flags)-c-o [email protected] $< else Cmd_cc_o_c = $ (CC) $ (c_flags)-c-o $ (@D)/.tmp_$ (@F) $< cmd_modversions = \ if $ (OBJDUMP)-H $ (@D)/.tmp_$ (@F) | Grep-q __ksy mTAB Then \ $ (call Cmd_gensymtypes, $ (kbuild_symtypes)) \ > $ (@D)/.tmp_$ (@f:.o=.ver); \ \ $ (LD) $ (ldflags)-r-o [email protected] $ (@D)/.tmp_$ (@F) \ T $ (@D)/.tmp_$ (@f:.o=.ver); \ rm-f $ (@D)/.tmp_$ (@F) $ (@D)/.tmp_$ (@f:.o=.ver); \ Else \ mv-f $ (@D)/.tmp_$ (@F) [email protected]; \ fi; endif
Back to top of page
Building and testing of modules
Before building an external module for the kernel, we need to prepare a kernel source tree (kernel source trees). The kernel source tree is a kernel tree that contains the system configuration and kernel header files. It should be noted that the Linux 2.6 kernel source tree is different from 2.4, the previous kernel only needs a set of kernel header files, but in the 2.6 kernel source tree, there are still some target files and tools, such as Scripts/mod/modpost. Listing 12 shows the kernel module precompilation from the kernel source to generate the kernel tree, but you can also use the Linux distribution Kernel source tree (the system kernel tree is generally stored in/lib/modules/<kernel version>/build, if present).
Listing 12. Pre-compiled kernel modules
# make Menuconfig # make Modules_prepare #
Of course, we must first generate kernel configuration files based on the hardware information of the host. config. You can use the command make menuconfig or make config to configure options related to the module (listing 13 corresponds to listing 14, which shows the kernel configuration options associated with the module). The setup options config_modules=y and config_modversions=y enable kernel support for version checking of modules. It is also important to note that module precompilation does not generate module.symvers files, even if you turn on the config_modversions option. So the best way is to fully compile the Linux kernel.
Listing 13. Configuring kernel module options using make Menuconfig
# make Menuconfig ---Enable loadable module support [] forced module loading [*] module unloading< C5/>[] forced module unloading [*] module versioning support [*] Source checksum for all modules
Listing 14. Module-related kernel configuration options
Config_modules config_module_force_load config_module_unload config_module_force_unload Config_modversions Config_module_srcversion_all
Kernel 2.6, we often write a Makefile file for the building of the module, but we can still use a module like kernel 2.4 to build commands. Listing 15 shows the make command built by the external module, where $KDIR is the absolute path to the kernel tree, $MDIR is the absolute path to the module that you want to build (if the internal module can use make config_ext2_fs=m ... )。
Listing 15. Building external Modules
# make-c $KDIR m= $MDIR [target] # make-c/lib/modules/2.6.38-10-generic/build m= $PWD/hello modules make : Entering directory '/usr/src/linux-headers-2.6.38-10-generic ' CC [M]/home/harris/work/samples/hello/hello.o Building modules, Stage 2. Modpost 1 Modules cc/home/harris/work/samples/hello/hello.mod.o LD [M]/home/harris/work/samples/hello/ Hello.ko make:leaving directory '/usr/src/linux-headers-2.6.38-10-generic '
Back to top of page
Conclusion
Although this article has tried to focus on the version checking mechanism of loadable modules, it still involves a lot of content. You'll need to take some time to understand what these seemingly unrelated modules are, such as the/proc,/sys file system, ELF (that is, executable and linkable format), to better understand the kernel loadable module and the module version check mechanism. In addition, as the article discusses the external modules of Linux 2.6, there is no clear description of the kernel kbuild system and Makefile files, but this is also important for the module.
Resolves version checking mechanisms for Linux kernel loadable modules