1、要解决的问题
Linux的内核模块(即ko文件)在编译时指定了可以运行在哪个内核版本。
例如,使用Ubuntu 16.04内核4.8.0-42-generic头文件编译的ko文件,只能运行这个内核版本中。
这就有个麻烦,Ubuntu内核版本更新速度非常快,如何内核更新为4.8.0-58-generic,那么这个ko文件就不能运行了,需要重新编译ko文件。
能否有简单的方法,让已有的ko文件运行不同的内核版本中呢?
有,本文介绍一种方法。
2、Linux内核是如何限制ko文件的执行?
ko文件运行在Linux内核中,运行时会调用Linux内核提供的接口。
由于Linux内核版本演进非常快,内核提供的接口可能经常发生变动。
为了保持Linux内核运行稳定,Linux采用的策略是:
- 编译ko文件时,确定了它调用的所有Linux内核接口的版本。
- 装载ko文件时,检查它调用的Linux内核接口版本,如果与当前Linux内核提供的接口版本完全致,则可以装载,否则拒绝装载。
2、内核接口版本是什么?
Linux内核为每个接口计算一个CRC整数值
例如:vfs_create 0xba70d5ae
编译ko时,针对是某个内核版本,把每个接口的CRC值都记录在ko文件中,即接口的版本信息。
装载ko时,与当前内核的接口CRC值进行比较,即接口版本比较。
3、修改ko文件中的CRC值能突破运行限制吗?
可以。
我在Ubuntu和CentOS上实验,通过修改ko文件中的接口CRC值,能够使之运行在不同的内核版本中。
4、如何实现呢?
Ubuntu和CentOS中有有相应的文本文件记录了指定版本内核的所有接口CRC值。
- Ubuntu:/boot目录下有所有已安装版本的abi文件,例如abi-4.8.0-58-generic。
- CentOS:/boot目录下前缀是symvers的文件。
只要把ko文件中所有使用的内核接口的CRC值改为与上述文件中的值,就能让ko文件运行了。
github上有一个开源程序能够修改ko文件的CRC值:
https://github.com/romeroperezabel/vermagic
我们可以修改这个程序,实现如下功能:
- 列出ko文件调用的所有内核接口
- 在记录CRC值的文件中,找到接口对应的CRC值
- 修改ko文件中接口的CRC值
这样,ko文件就能运行在相应的内核版本中了。
5、注意
有可能修改成功,也有可能修改失败,例如新版本把某个接口取消了。
如果修改失败,就得重新编译ko文件了。
即使修改成功,也可能运行失败,严重的会导致系统无法启动,所以要特别注意,可以先在虚拟机上测试。
如果运行失败,也得重新编译ko文件了。
6、其它
最近遇到一个编译后ko文件无法运行的问题,解决方法如下。
repoline的问题:insmod一个简单ko,出现错误