Home Linux内核模块签名与版本检查机制
Post
Cancel

Linux内核模块签名与版本检查机制


内核模块签名机制

linux内核从3.7 开始加入模块签名检查机制, 校验签名是否与已编译的内核公钥匹配。目前只支持RSA X.509验证, 模块签名验证并非强制使用, 可在编译内核时配置是否开启。

CONFIG_MODULE_SIG: Module signature verification

开启该选项后,内核加载该模块时会对内核模块的签名进行检查。默认情况下,在加载没有签名或签名不正确的内核模块时,仅打印一条提示信息,将内核标记为tainted,然后继续加载该模块。

CONFIG_MODULE_SIG_FORCE: Require modules to be validly signed

开启该选项后,在加载无签名或签名不正确的内核模块时,内核会直接拒绝加载签名有问题的内核模块。

CONFIG_MODULE_SIG_ALL: Automatically sign all modules

kbuild在执行make modules_install时对所有的内核模块进行签名,若该选项未设置,则需要手动调用scripts/sign-file对内核模块进行签名

CONFIG_MODULE_SIG_HASH: 设置签名算法

包括:

  • CONFIG_MODULE_SIG_SHA1:sha1
  • CONFIG_MODULE_SIG_SHA224:sha224
  • CONFIG_MODULE_SIG_SHA256:sha256
  • CONFIG_MODULE_SIG_SHA384:sha384
  • CONFIG_MODULE_SIG_SHA512:sha512

内核和驱动中的版本信息

Linux的内核版本号KERNELRELEASE在编译的过程中生成,存储在include/config/kernel.release文件中。

vermagic用于内核模块的版本检查,Linux内核的vermagic可以通过cat /proc/version来查看,而对于kernel module,可以通过modinfo来查看。其值由kernel Makefile中的VERMAGIC_STRING表示,其中UTS_RELEASE即为内核的KERNELRELEASE。:

1
VERMAGIC_STRING = 	<UTS_RELEASE> ["SMP"] ["preempt"] ["mod_unload"]["modversions"]

为了确保Linux kernel和kernel module的二进制兼容性,会对导出符号进行CRC校验。kernel中导出的每一个符号都有一个CRC校验,而module中保存了每一个使用到的由kernel导出的symbol的CRC校验,在module加载时会检查二者是否匹配,如果不匹配将不会加载。

如果启动了CONFIG_MODVERSIONS,则每个通过EXPORT_SYMBOL定义输出的符号名都会计算一个CRC校验码。在编译kernel/module完成后,生成的Module.symvers文件中包含了kernel的所有的导出符号的CRC校验码。当module引用了kernel或其他module导出的符号时,在编译过程中需要读取kernel或者其他module的Module.symvers,而这些Module.symvers应该放到当前module的源码目录下,或在Makefile中通过KBUILD_EXTRA_SYMBOLS=来指定依赖的模块的Module.symvers的内容。

在编译生成的module.ko中,存在一个__versions section,其中保存了module所引用的符号和对应的CRC验证码,可以通过modprobe -dump-modversions来查看完整信息:

1
2
3
4
5
6
7
8
$ modprobe -dump-modversions ixgbe.ko
	0x235a30d9      module_layout
	0x452ba683      ipv6_ext_hdr
	0xe2d5255a      strcmp
	0xb8b9f817      kmalloc_order_trace
	0x72128032      secpath_set
	0xd0760fc0      kfree_sensitive
	......

模块加载时的检查步骤

内核在加载模块时,首先会进行模块签名验证,然后进行版本检查。

版本检查分为vermagic检查和CRC校验检查,具体过程由CONFIG_MODVERSIONS相关控制:

  • kernel打开CONFIG_MODVERSIONS,module不打开CONFIG_MODVERSIONS:将不会检查CRC,但是会完整匹配vermagic,此时kernel和module的vermagic的modversions不一致,模块将加载失败。
  • kernel和module都打开CONFIG_MODVERSIONS:检查CRC,然后匹配vermagic第一个空格后的部分,例如对于vermagic: 5.12.10 SMP mod_unload modversions ,只会匹配SMP mod_unload modversions
  • kernel不打开CONFIG_MODVERSIONS,module打开CONFIG_MODVERSIONS:完整匹配kernel和module的vermagic,但是因为二者modversions不同,模块加载失败。
  • kernel和module均不打开CONFIG_MODVERSIONS:完整匹配vermagic,module加载成功。

如何关闭模块签名验证

可以通过strip --keep-file-symbols <module_name>删除指定模块的签名。

内核中存在kernel_lockdown机制,用于阻止对于正在运行的内核映像的直接或间接地未经授权地访问,该机制开启与否由.config中的CONFIG_SECURITY_LOCKDOWN_LSM控制。通过将 CONFIG_SECURITY_LOCKDOWN_LSMCONFIG_MODULE_SIG设置为n,编译出的驱动将不再包含签名,对应的内核在加载模块时也不会验证签名的正确性。而如果仅将CONFIG_MODULE_SIG设置为n,在后续通过make olddefconfig时,由于lockdown的存在,将会自动重新开启CONFIG_MODULE_SIG

如何忽略版本检查

在modprobe中提供了两个选项,用于在加载模块时忽略vermagic或CRC检查:

–force-vermagic Every module contains a small string containing important information, such as the kernel and compiler versions. If a module fails to load and the kernel complains that the “version magic” doesn’t match, you can use this option to remove it. Naturally, this check is there for your protection, so using this option is dangerous unless you know what you’re doing. This applies to any modules inserted: both the module (or alias) on the command line and any modules on which it depends.

–force-modversion When modules are compiled with CONFIG_MODVERSIONS set, a section detailing the versions of every interfaced used by (or supplied by) the module is created. If a module fails to load and the kernel complains that the module disagrees about a version of some interface, you can use “–force-modversion” to remove the version information altogether. Naturally, this check is there for your protection, so using this option is dangerous unless you know what you’re doing. This applies any modules inserted: both the module (or alias) on the command line and any modules on which it depends.

-f, –force Try to strip any versioning information from the module which might otherwise stop it from loading: this is the same as using both –force-vermagic and –force-modversion. Naturally, these checks are there for your protection, so using this option is dangerous unless you know what you are doing. This applies to any modules inserted: both the module (or alias) on the command line and any modules it on which it depends.

Reference

1.kernel_lockdown(7) - Linux manual page (man7.org)

2.深入分析Linux kernel安全特性: 内核模块签名 - 知乎 (zhihu.com)

3.LINUX内核模块签名

4.LINUX内核模块版本检查

This post is licensed under CC BY 4.0 by the author.