arm核心模块(openEuler Meetup演讲分享 | ARM架构下的内核热补丁技术)

arm核心模块

友情提示:全文2500多文字,预计阅读时间3分钟
近日,openEuler开源社区举办2021年Meetup技术交流沙龙,云能力中心IaaS产品部丁翔、胡丽娜、卫迎泽三位专家应邀出席会议,共同探讨了内核热补丁、计算虚拟化、Ceph分布式存储等核心开源技术。
会上,云能力中心IaaS产品部基础软件专家丁翔发表了主题为“ARM架构下的内核热补丁技术”的演讲,讲解了云能力中心操作系统层面的产品在ARM平台的实践和优化,展现了云能力中心在基础架构上的两手抓战略,X86平台与ARM平台齐头并进,优秀的IaaS底层产品支撑移动云用户的上云使用需求。

一、背景介绍
内核热补丁技术目前已经比较成熟,如redhat开发的kpatch,suse开发的kgraft,在4.0内核合入主线的livepatch,但内核热补丁只支持少数的架构,如x86、s390,不支持ARM64,而移动云也部署了一批ARM64服务器,所以现网对支持ARM64架构的内核热补丁也有了需求,基于此,我们开发了支持ARM64架构的内核热补丁功能。

二、内核热补丁技术原理
图1 | 热补丁流程

左边的流程是没有打补丁的时候,那么可以看到就是执行原来函数的流程,右边是打过补丁的函数,流程会有比较大的变化,目前我们的内核热补丁是通过工具kpatch编译处理的,也是使用kpatch工具去打热补丁的,在打热补丁的时候,热补丁的内核模块会在符号表中找到需要打补丁的函数,然后向ftrace注册一个处理函数。那么需要打热补丁函数开始的nop指令就会被替换为调用这个处理函数,在原函数被调用时,ftrace就会调用这个处理函数。然后,ftrace处理程序修改堆栈上的返回指令指针(IP)地址并返回给ftrace,然后恢复原函数的参数和堆栈,并“返回”到新函数。这样就完成了函数替换,后面就会执行新函数的流程,热补丁就生效了。

三、内核热补丁生效流程
图2 | 热补丁函数流程

打补丁后,原来的第一条指令nop就变成了call fentry,那这个fentry最终其实是进入了ftrace的处理流程,由ftrace调用热补丁注册的处理函数,那么这个处理函数做的主要的事情其实很简单,就是修改了ip指针,将它指向的新的函数,就是修改过的函数,当处理函数返回后,最终ftrace会使用这个修改过的ip指针返回,这样就进入了新函数的流程,原来的函数流程就不再执行了。

四、内核热补丁是如何生成的
图3 | 热补丁编译流程

编译生成内核热补丁模块的命令其实很简单,只要kpatch-build test.patch -n kpatch-test 就行了,如果源码srpm包,或者与当前系统内核版本不一致,那么还需要装debuginfo包,这张图是将source diff patch转换为一个热补丁模块的过程。基本原理是将打过补丁的内核重新编译并对比前后二进制文件,最终生成包括替换函数的补丁模块,具体步骤如下:
首先编译旧的内核源码(original src),生成original objects;
第二步是内核源码打上补丁(pached src),重新编译新内核并找到有改动需要重新编译的objects,新的为pached objects;
第三步对比original object跟patched objects,将需要替换的函数及符号信息导出到output objects;
第四步最后将所有的output objects链接并生成热补丁模块,至此编译就完成了。

五、ARM64内核热补丁
图4 | ARM64热补丁
支持ARM64架构的内核热补丁需要解决哪些问题?第一个问题就是ARM64不支持fentry,在X86上,调用指令通过硬件将返回地址放入堆栈中,在ARM64上,调用指令(BL或BLR)将返回地址放到链接寄存器中(LR),所以LR寄存器的内容是变化的,需要对寄存器内容进行保存,所以支持x86的mfentry就不能用于ARM64,那么在GCC8版本添加了patchable-function-entry,这个特性是在编译的时候在函数开头加入N个nop指令,这样就实现了类似mfentry的功能。
第二个问题是ARM64不支持FTRACE_WITH_REGS,那么suse在19年向社区提交的了支持arm64的FTRACE_WITH_REGS功能,这个补丁经过多次修改后最终合入了内核主线,这个补丁主要做的事情就是指定了编译时在函数开头添加nop指令的数量,目前是添加了2条nop指令,然后在开启ftrace后对这2条nop指令进行了修改,图4的表中可以看出,在编译后函数开头多了2条nop指令,在没有对函数trace时,会将第一条nop指令替换为保存LR的指令,第二条指令还是nop,当函数被trace后,会将第二条指令替换为bl指令,来跳转到ftrace注册的钩子函数上,将寄存器入栈。
解决了这2个问题后,ARM64支持热补丁基本机制其实就具备了,那么我们在内核的改动主要就是对ARM64的pc指针地址进行修改,使指针能正确指向修改过的函数,除了在内核态的改动外,编译热补丁的工具kpatch-build也需要修改,主要的修改点有2个,一个是对重定位类型进行了修改,使kpatch-build生成正确的补丁文件,第二个是对一些符号以及结构查找的修改,使这些适配ARM64,那么这些做完之后,ARM64就可以正常支持热补丁了。

六、案例分享
在某云主机环境上,重启ovs服务内核有时会crash,根据crash的日志分析后证实是内核vxlan模块的一个BUG,该漏洞详细描述链接如下:
[PATCH net] vxlan: Fix GRO cells race condition between receive and link delete – Stefano Brivio (kernel.org)
这个BUG是由于在ovs在重启时会删除vxlan设备,而如果此时还在收包,按照原来代码的流程,vxlan_delink会删除gro_cells,但vxlan_recv还在使用,这将会导致在处理包的过程中内核crash,所以修复补丁是将删除gro_cells的位置放到了vxlan_unint 中。由于这个补丁修改量小,不涉及函数语义、结构体成员等修改,可以使用热补丁修复。而线上环境重启修复会影响客户的业务,所以我们优先采用了内核热补丁的方式,将社区补丁制作成内核热补丁并利用我们自研的热补丁工具完成批量的在线部署,成功修复了这个BUG。
END

为大家提供了本次演讲的PPT,感兴趣的可以自行下载~

下载链接:http://pan.cmsoft.com.cn/drive/fileextcenter.do?data=fb9a1558f7277cb27eb151aa1248f76chCh7b1ZoI 
密码:R5DWKW

作者简介
丁翔
中国移动云能力中心IaaS产品部软件开发工程师,操作系统内核专家,负责BC-Linux操作系统内核建设。
 往期 · 精选 
1、演讲分享|IaaS产品部专家团队参加openEuler Meetup苏州站技术交流沙龙
2、虚拟化顶级技术会议KVM Forum演讲分享 | 移动云KVM共享云盘技术实践
3、2020全球开源基础设施技术峰会分享 | 自研软硬一体化加速方案

arm核心模块相关文章

版权声明