开源工具 CAdapt 发布:适配 GLIBC 与内核模块版本
分享一个开源小工具CAdapt - 书生执笔画浮沉
开源小工具 CAdapt 可将已编译的 Linux 可执行程序适配到指定 GLIBC 版本,并强行适配内核模块到目标内核版本。该项目由 2022 年的 CAdapt 与 2025 年的 UpModule 于 26.10.02 合并而成,26.10.12 使用 codex 完成代码质量检查与 bug 修复。
作用简述
将已编译的 Linux 可执行程序与某个 GLIBC 版本进行兼容
将已编译的 Linux 驱动程序强行适配某个内核版本
关于使用局限性及仓库地址见文章末尾
背景
早期在向低版本glibc环境部署工具链时,总是会遇到找不到高版本glibc符号的问题
于是就只能在低版本环境从源码构建出高版本glibc
然后用LD_LIBRARY_PATH、LD_PRELOAD指向它或者用patchelf工具批量修改二进制文件的rpath和新的动态链接器路径
但这个方法太麻烦了,让我不由得产生一个疑问,既然报错的符号名称一致,为什么动态链接器非要匹配指定版本的符号?
既然它能知道elf文件所需的版本,那么这个版本肯定被记录在elf文件中了,那么能不能像修改文本文件一样,把版本调低呢?
CAdapt【2022】
于是就从网上找elf文件格式资料、相关源码
果珍,让我找到了一个很久以前别人用c实现的代码
然后就是编译验证,成功后就是古法分析、注解,然后改造了
由此,我的第一版CAdapt就诞生了
当然在后面使用过程中也暴露出一些问题,后续又进行了一些修复
UpModule(2025)
UpModule 的起因也很简单
就是因为后面做驱动开发时遇到了类似的问题
有时内核只是更新了一个小版本,原本正常的驱动就装载不上了
随后举一反三,既然以前做CAdapt可以直接修改已编译好的elf文件达到兼容的目的
那么同样修改已经编译好的驱动文件,是否也能达到此类目的呢
于是便尝试让Ai仿照着CAdapt的做法,输出一套用于内核模块硬兼容的代码
但不知道是Ai出于对于我这种行为的排斥,还是对内核代码并不了解,一直劝退我,导致最终未果
后面依旧是扒内核源码,分析内核模块装载时的校验逻辑,然后在代码中反向操作得以实现
Merge(26.10.02)
国庆节闲来无事,突然想到既然两者都属于同一类型的小工具,为何不合并成一个
后面再有类似需求再逐渐追加功能,慢慢发展成类似patchelf那种的实用工具呢
虽说现在Ai工具盛行导致工具廉价,但总能节省点token吧
于是使用gemini对两者进行了合并
Fix(26.10.12)
开始使用codex,刚好用这种小项目练习一下
于是便让他检查代码质量、以及有没有bug
结果这世界上又多了个回车战士……
注意事项
说了这么多,讲讲局限性吧
对于glibc的适配:
- 要保证没有用到高版本glibc中特有的符号
- 例如有些时间相关的……
- 要确定被修改的这个符号使用的一些数据结构没有发生改变,否则即使提示修改成功,实际运行也会崩溃
- 比如某个结构体在低版本glibc中时32字节,高版本中变成了64字节,即便符号版本被降级成功,依旧ABI版本不兼容
以上两种情况对 kmod 也适用,同时对于启用了 CONFIG_MODVERSIONS 的内核模块,还需要获取目标内核导出符号对应的 CRC 信息
如果找不到对应的信息,就需要从系统中已安装的驱动中提取,如果提取到的符号覆盖了你驱动中使用的符号,那么就可以成功,反之失败
所以在编写驱动之初,就应该限制使用的函数数量以及更多的使用常用内核函数,这样的话再配合当前的工具就能在一定程度上提高驱动的兼容性
还有一点虽然不常见但也要注意,对于启用了强制模块签名校验的系统,修改后的模块还需要满足相应的签名要求。
仓库地址
来源:博客园 · cnblogs.com