首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

解析 Linux 内核可装载模块的版本检查机制-模块的装载与卸载

解析 Linux 内核可装载模块的版本检查机制-模块的装载与卸载

上述中,我们在装载模块时使用了工具 insmod。在 Linux 2.6 中,工具 insmod 被重新设计并作为工具集 module-init-tools 中的一个程序,其通过系统调用 sys_init_module(您可查看头文件 include/asm-generic/unistd.h)衔接了模块的版本检查,模块的装载等功能(如 所示)。module-init-tools 是为 2.6 内核设计的运行在 Linux 用户空间的模块装卸载工具集,其包含的程序 rmmod 用于卸载当前内核中的模块。
图 3. 模块的装卸载表 1. 工具集 module-init-tools 中的部分程序名称说明 insmod 装载模块到当前运行的内核中 rmmod 从当前运行的内核中卸载模块 lsmod 显示当前内核已加装的模块信息 modinfo 检查与内核模块相关联的目标文件,并打印出所有得到的信息 modprobe 利用 depmod 创建的依赖关系文件自动加载相关的模块 depmod 创建一个内核可装载模块的依赖关系文件,modprobe 用它来自动加载模块
值得一提的是在 module-init-tools 中可用于模块装卸载的程序 modprobe。程序 modprobe 的内部函数调用过程正如您所想与 insmod 类似,只是其装载过程会查找一些模块装载的配置文件,且 modprobe 在装载模块时可解决模块间的依赖性,即若有必要,程序 modprobe 会在装载一个模块时自动加载该模块依赖的其他模块。
其他一些细节从用户空间装载模块到内核时,Linux 还对用户权限进行了检查。模块的装载须是获得 CAP_SYS_MODULE 权限的超级用户,这正是模块装载时最先检查的内容(见 )。在 Linux 2.6 中,模块在构建时生成了一些临时文件,如 .o 文件、.mod.o 文件等。了解这些文件的生成有助于我们更好的理解 Linux 2.6 的内核模块构建过程以及版本信息的检查等内容。文件 .o 是模块代码(即 .c 文件)经编译后获得的目标文件,文件 .mod.o 则对应文件 .mod.c。文件 <module>.mod.c 是对 <modulue>.c 的扩展,展示了文件 kobject-example.mod.c 的内容 ( 即模块 kobject-example.ko 的 .mod.c 文件 ),您可见到与模块版本检查相关三个小节。
清单 8. 文件 kobject-example.mod.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 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");




清单 8 中显示了模块 kobject-example.ko 中的三个 section 以及宏 MODULE_INFO,最后一行 srcversion 则需开启内核配置选项 MODULE_SRCVERSION_ALL。经上述,我们知道这三个 section 正是模块版本检查的附加信息。我们通过工具 objdump 查看 .modinfo 小节(见 , 即模块的 vermagic 信息)。<module>.ko 的附加信息合并自文件 <module>.o 与文件 <module>.mod.o。内核工具 modpost 完成了一这步骤,且该工具是 Linux 2.6 内核模块构建时所必须的。
清单 9. 使用工具 objdump 查看 .modinfo 小节
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 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 00                          /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
...




经上述,我们可知内核树的顶层 Makefile 文件包含了内核版本的信息,且该信息经编译后被添加到模块的(头文件 include/generated/utsrelease.h 保存的内核版本信息来自顶层 Makefile)。中,工具 lsmod 打开文件 /proc/modules 查询当前内核中已装载的模块(见清单 10),文件 /proc/modules 还被 rmmod 在卸载模块时使用。另外,若您在装载模块 hello.ko 后没能在终端下看到相应的字符串输出,则需检查文件 /proc/sys/kernel/printk,并重设下消息级别。
清单 10. 工具 lsmod 的使用
1
2
3
4
5
6
7
8
9
10
# 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




Linux 2.6 构建模块时工具 modpost 被 scripts/Makefile.modpost 调用,生成 <module>.mod.c 及文件 Module.symvers(见 )。在开启内核选项 CONFIG_MODVERSIONS 之后,文件 Makefile.Build 会调用工具 genksyms(现位于内核树 scripts/genksyms 目录下,在 Linux 2.4 时是模块工具集 Modutils 的一部分)生成 CRC 信息(见 )。其中代码 call cmd_gensymtypes 就是对工具 genksyms 的调用。另外一个较为明晰的方式是,使用工具 objdump 或 readelf 查看相关的 ELF 小节,并使用 make – n 查看模块构建过程。
清单 11. 文件 Makefile.Build 的部分内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ifndef CONFIG_MODVERSIONS
cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $<
else
cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
cmd_modversions =              \
if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then  \
   $(call cmd_gensymtypes, $(KBUILD_SYMTYPES))    \
       > $(@D)/.tmp_$(@F:.o=.ver);      \
                 \
   $(LD) $(LDFLAGS) -r -o $@ $(@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) $@;        \
fi;
endif

返回列表