Sholck

不积跬步,无以至千里.不积小流,无以成江海

0%

动态模块加载异常

动态模块加载异常

背景

动态模块加载,出现以下异常

1
disagrees about version of symbol module_layout"

原理

kernel编译会生成vmlinux.symvers和Module.symvers两部分记录vmlinuz和模块的接口的symbol,动态模块编译时会生成xxx.mod.c,其中记录了动态模块用到的接口symbol,在加载模块时会去匹配接口的symbol是否和Module.symvers记录的一致,如果不一致,则提示错误。

分析

动态模块xxx.mod.c中的module_layout symbol

1
2
3
4
5
6
static const struct modversion_info ____versions[]    
__used __section("__versions") = {
{ 0x97f53857, "module_layout" },
{ 0x92997ed8, "_printk" },
{ 0xbdfb6dbb, "__fentry__" },
};

内核vmlinux.symvers中的module_layout symbol

1
0x4709b79f      module_layout   vmlinux EXPORT_SYMBOL 

内核Module.symvers中的module_layout symbol

1
0x97f53857      module_layout   vmlinux EXPORT_SYMBOL

发现动态模块中的和Module.symvers的一致,但是和vmlinux.symvers的不一致,而每一次make bzImage都会导致vmlinux.symvers更新,不会去生成更新Module.symvers,导致Module.symvers symbol过旧,因此需要重新make modules

代码部分

实现逻辑见kernel/module.c ,通过CONFIG_MODVERSIONS来编译控制

1
return check_version(info, "module_layout", mod, fsa.crc); 

解决

  • 第一种:make modules,重新动态模块编译
  • 第二种:更新.config,删除CONFIG_MODVERSIONS

验证

插入模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

➜ initramfs modinfo /github/busybox/initramfs/x86-busybox-rootfs/hello.ko
filename: /github/busybox/initramfs/x86-busybox-rootfs/hello.ko
license: Dual BSD/GPL
srcversion: 89A8475A71641B4AAA82542
depends:
retpoline: Y
name: hello
vermagic: 5.17.0+ SMP preempt mod_unload

➜ initramfs qemu-system-x86_64 -m 1024 -smp 2 -hda rootfs.img -kernel /github/busybox/initramfs/x86-busybox-rootfs/vmlinuz-5.17.0+ -s -append "root=/dev/sda rdinit=init crashkernel=128M console=ttyS0 rw" -nographic
...
/ # ./init

Boot took 15.51 seconds

/ # insmod hello.ko
[ 22.306823] random: fast init done
[ 22.322005] hello: loading out-of-tree module taints kernel.
[ 22.323224] hello: module verification failed: signature and/or required key missing - tainting kernel
[ 22.327473] Hello, world

/ # lsmod | grep -n "hello"
1:hello 16384 0 - Live 0xffffffffc00bb000 (OE)
/ # cat /proc/modules
hello 16384 0 - Live 0xffffffffc0369000 (OE)

卸载模块

modprobe -r 会在/lib/module/$(uname -r) 下去寻找卸载的模块

1
2
3
4
5
/ # mkdir -p /lib/modules/5.17.0+
/ # cd /lib/modules/5.17.0+
# /lib/modules/5.17.0+ # cp /hello.ko .
# /lib/modules/5.17.0+ # modprobe -r hello
[ 487.404929] Goodbey, cruel world