点击围观!腾讯 TAPD 助力金融行业研发提效、敏捷转型最佳实践! 了解详情
写点什么

应用程序热补丁(三): 完整的设计与实现

  • 2019-11-12
  • 本文字数:4134 字

    阅读完需:约 14 分钟

应用程序热补丁(三): 完整的设计与实现

在前两篇文章介绍了应用程序热补丁的关键技术:


  • 修复运行时进程的函数;

  • 加载热补丁到进程中;

  • 自动生成热补丁等等。


这些是组成应用程序热补丁技术框架的关键部分,但是在生产环境中使用热补丁技术还需要考虑适应现代软件的属性、热补丁的安全性、以及在运营中对热补丁的管理等等。


通过介绍 UCloud 应用程序热补丁框架的设计理念和框架中各个组件,我们会解决以下实践中遇到的问题:


  • 热补丁的管理(加载、卸载、激活、回滚热补丁等);

  • 打入热补丁时的安全检查(简单说是什么时候打入热补丁是安全的);

  • 热补丁对多线程的支持等等。

应用程序热补丁的意义

介绍 UCloud 应用程序热补丁框架之前,首先介绍一下我们为什么研发和使用热补丁技术。


目前主流的热补丁技术,例如 Ksplice、kpatch、kGraft 以及后来的 livepatch 等都是特别针对 Linux 内核的热补丁技术,可以在不重启系统的情况下,修复内核缺陷。我们一般称为内核热补丁。


UCloud 作为公有云的提供者,必须保证客户和业务本身的可用性。我们使用了内核热补丁修复了若干内核问题,避免了重启系统导致的服务中断,保证了操作系统本身的可用性。


在此基础上,我们的下一个目标是提高核心组件中的单点可用性。例如虚拟化的核心组件 QEMU,虽然作为单点程序运行,但是可用性的要求和内核是一致的。虽然 QEMU 本身支持在线迁移,可以迁移客户的虚拟机到新版本的 QEMU 上,但是迁移本身比较笨重。在迁移过程中会牵扯多个模块,例如网络、存储等,同时迁移时间和虚拟机的 downtime、break time 在运营上也会带来挑战。


对比 QEMU 通过在线迁移升级,使用热补丁修复极快,并且对虚拟机周边环境没有依赖,可以对用户的虚拟机做到静默升级。由于热补丁本身的天然属性,热补丁更适用于代码改动较小的修复(例如安全漏洞),而在线迁移升级比较适用于大版本的升级。


在 UCloud 我们通过热补丁修复了若干次 QEMU 的缺陷和安全漏洞,极大提高了可用性和安全性。因此我们认为对于代码改动较小的问题时,热补丁是一个完美的解决方案。


为什么要自研应用程序热补丁技术?答案也很简单,我们无法找到一个实用并且易用的应用程序热补丁技术,同时也由于我们已经在内核热补丁领域的具有一定的积累,所以决定敢为人先、自研应用程序热补丁技术。

设计理念

01 提出需求

介绍设计理念之前,首先应该提出应用程序热补丁在 UCloud 云平台的需求:


  1. 应用程序热补丁的适用场景和内核热补丁是一致的,目的是修复缺陷,而不是增加功能和升级版本。所以应用程序热补丁必须允许函数级别上的修改(不论是本地函数还是全局函数);

  2. 应用程序热补丁必须是安全的,也就是打入热补丁的前后进程的状态必须一致,热补丁只会操作修改的函数,不会影响进程的正常运行;

  3. 应用程序热补丁必须支持云平台环境中现代软件具有的特性,比如说 Linux x86_64、多线程等等;

  4. 热补丁必须由工具来构建,也必须要由工具来管理(加载卸载等);

  5. 热补丁必须同时支持回滚、支持一个进程多次热补丁修复;

  6. 降低热补丁运营的难度;


我们针对这些需求,设计出如下的应用程序热补丁框架。

02 设计思路

  • 支持修复函数级别的、并且可以自动化生成热补丁的工具;

  • 支持多线程、热补丁安全检查、多热补丁状态管理的热补丁加载工具;

  • 运行中的应用程序应记录热补丁的信息和状态,可供外部工具查询。


或者简单来说,我们要做到,拿到源码和 patch 就能通过工具自动生成热补丁,热补丁可以安全的打入运行的多线程应用程序中(不会引起程序的错乱和崩溃),并且支持打入多个热补丁。打入后的热补丁可以被回滚取消,可以查询当前应用程序中热补丁的状态和信息。

03 框架组件

这个框架的设计我们通过以下组件实现:

Creator

  • 负责通过 patch 和源码自动化生成热补丁。

  • 支持函数级别修复,不论本地函数还是全局函数。

Loader

  • 负责加载热补丁到目标进程中,也负责管理热补丁(类似于客户端程序)。

  • 目标进程支持 Linux x86_64、多线程等。

  • 支持热补丁安全检查。

  • 支持对热补丁状态的操作(例如加载、卸载、激活、回滚查询等等)。

Core Runtime

  • 负责记录多个热补丁的状态和信息,同时提供热补丁通用操作。

  • 作为热补丁模块的通用运行时框架被 Loader 加载到目标进程中。

  • Loader 对热补丁状态的操作最终由 Core Runtime 在目标进程空间中执行。

热补丁(补丁本身)

  • 负责提供修复后的替换代码和额外信息。

  • 被 Loader 加载到目标进程中,注册自己的信息到 Core Runtime。

  • 在激活后使用自身包含的替换代码代替有问题的函数。


组件之间协作如下图所示,Creator 工具根据程序源码和 patch 生成热补丁模块,然后 Loader 将热补丁模块加载到目标进程 Process 的地址空间里,最后热补丁和通用运行时 Core Runtime 一起完成热修复。


实现方法

接下来分别讲各个组件的实现:

01 Creator

基于对多种内核热补丁技术的理解,我们认为应用程序的热补丁也是可以通过工具自动生成的。虽然相比内核,应用程序的格式更加复杂、编译链接的过程也更不固定,但是自动生成热补丁应该是可行的。


我们知道,编译源代码之后会生成目标文件,将单个或多个目标文件链接可以生成可执行文件。目标文件和可执行文件都是 ELF 格式(Executable and Linkable Format)。ELF 是一种标准且通用的文件格式,Linux 上的可执行文件、目标文件、库、core dump 都是 ELF。


Creator 工具根据 ELF 标准的格式,解析修复前后的目标文件,找到前后不同的函数,提取出差异(包括改变和新增的函数),连同差异本身的属性信息,生成一个动态链接库格式的热补丁。如下图所示:



之前的文章介绍过二进制比较生成热补丁替换代码,这里不再赘述。

02 Loader

Loader 工具作为一个客户端程序,操作目标进程 Process,包括热补丁的加载、激活、回滚、卸载、查看等。如下所示:



Loader 利用了 ptrace 调用。Loader 通过 ptrace 可以对 Process 的内存、寄存器进行读写,改变 Process 的运行状态,也可以捕获 Process 的信号。这样 Loader 可以停止 Process 的运行,并根据 AMD64 ABI 对内存和寄存器进行修改,使 Process 执行 dlopen 等函数,加载热补丁到 Process 的地址空间中,或者执行其他热补丁的操作。热补丁被加载之后,在 /proc/pid/maps 文件中可以看到。


Loader 如何利用 ptrace 加载热补丁在之前的文章中有详细描述,不再赘述。


Loader 随后会停止 Process 所有的线程,准备激活热补丁,此时 Loader 需要进行一致性检查,也就是查看热补丁的激活对当前的所有线程来讲是否安全。需要检查的是热补丁的需要替换的函数是否在线程当前函数调用栈上,如果在调用栈上,说明现在是不安全的,激活热补丁不能保证一致性。


在停止所有线程的时候,首先需要得到全部的线程信息,可以通过 libthread_db 库与进程中 libc 进行交互得到线程的信息,也可以通过 /proc/pid/tasks/ 目录从内核中直接得到线程的信息。在停止所有线程之后,需要再次获取所有线程信息,查看是否有新增线程,如果有需要停止新增线程。重复以上动作直到没有新线程出现。

03 Core Runtime

在一个进程的生命周期中,可能需要多次热补丁修复,同时多个热补丁也会使用一些通用的功能,因此需要一个通用的核心模块来提供通用功能,并且记录进程中每个热补丁的信息。这个通用模块作为一个动态链接库,我们叫做 Core Runtime。


Loader 在加载热补丁时,首先需要加载 Core Runtime 到进程的地址空间,对进程而言,Core Runtime 只需要加载一次。


在热补丁被加载到进程的地址空间后,通过构造函数,首先向 Core Runtime 提供自己的信息,注册到 Core Runtime 里,然后将热补丁中差异函数的需要重定向的部分手动计算重定向。在激活热补丁的时候,Core Runtime 会根据热补丁注册时得到的信息,保存旧函数,并把旧函数入口位置替换成跳转到新的函数的机器码,完成热修复。如下所示:



在回滚热补丁的时候,Core Runtime 把旧函数入口位置恢复,完成回滚。


Core Runtime 同时可以管理多个热补丁,以热补丁的名字作为 ID,区分不同的热补丁,记录必要的信息。


如下所示:


04 热补丁(补丁本身)

这里的热补丁指的是狭义上的作为动态链接库被 Loader 加载到目标进程 Process 中的热补丁。


热补丁由 Creator 产生,包含了替换代码和一些动态信息(比如新旧函数的地址、大小、重定向信息等)。热补丁被加载后,包含的函数和变量就存在于目标进程的地址空间中。热补丁激活以后,所有对老函数的访问,都会重定向到热补丁地址范围内的新函数。


如下所示:


总 结

Creator、Loader、Core Runtime、热补丁这四者构成了 UCloud 热补丁技术框架,这四个组件相辅相成,互相协作完成热补丁。


Creator 负责生成热补丁,Loader 负责热补丁的进程外管理(包括加载、卸载、激活、回滚热补丁等),Core Runtime 负责热补丁的进程内管理(记录热补丁、备份旧函数、恢复旧函数等)。虽然是四个组件,但是都必须遵守同一个热补丁规格标准,这样才能共同完成热补丁的工作。


通过这个框架,极大降低了我们制作热补丁、打入热补丁和运营热补丁的难度。


例如,一个 QEMU 安全漏洞修复的流程可以简化为:


  1. Creator 通过 QEMU 源码和漏洞修复 patch 生成热补丁。

  2. 热补丁被 Loader 打入正在运行的应用程序中(加载并且激活)。

  3. (可选)对运行中的应用程序查询热补丁的状态和信息。

  4. (可选)对已经打入的热补丁进行回滚和卸载。


值得指出的是,目前不是全部 patch 都可以自动生成热补丁,原因是极少部分由于程序修改复杂,但是可以通过手动修改 patch 简化代码或者简化逻辑做到可以自动生成热补丁。大约 90% 的 patch 在无需修改的情况下都能自动生成热补丁。


在一些特定场景下,我们通过第一篇文章(《应用程序热补丁(一):几行代码构造免重启修复补丁》)中介绍的热补丁技术手动编写热补丁即可,无需使用复杂的自动生成热补丁技术。


另外,目前 UCloud 应用程序热补丁技术支持 Linux C 语言程序,但对于其他编译型语言解决思路基本一致(例如 C++ 等)。


在 UCloud,我们利用应用程序热补丁修复了若干紧急安全漏洞和缺陷,在关键时刻迅速解决问题,相比于传统的软件升级方式,解决问题更加及时。


希望通过一系列的文章填补目前应用程序热补丁的空白部分,使更多人了解热补丁的技术原理,让热补丁技术给更多人带来更多的价值。


本文转载自公众号 UCloud 技术(ID:ucloud_tech)。


原文链接:


https://mp.weixin.qq.com/s/0u_HSfr2NP2u6TLJeg-DtQ


2019-11-12 16:382066

评论

发布
暂无评论
发现更多内容

架构实战 - 模块 7 作业

mm

架构实战营 异地多活

零代码应用搭建规范建议

明道云

数据可视化图表系列解析——雷达图

Data 探险实验室

数据分析 可视化 数据可视化 图表 可视化数据

软件测试/测试开发 | 接口测试中,请求超时该怎么办?

测试人

软件测试 自动化测试 接口测试 测试开发

再获认可!天翼云荣获“行业应用实践优秀合作伙伴”授牌

天翼云开发者社区

OpenHarmony社区运营报告(2022年12月)

OpenHarmony开发者

OpenHarmony

【Linux】Linux命令快速学习神器tldr、cheat介绍和使用

懒时小窝

Linux tldr cheat

多活数据中心链路智能调度场景

智维数据

数据中心 DNS 智能运维 应用交付平台 可视化数据

重新思考边缘负载均衡

俞凡

架构 netflix 大厂实践

厉害了!天翼云位列中国医疗云基础设施服务市场榜首

天翼云开发者社区

MySQL:删除一张表中的前10万行数据,哪种方式效率更高?

程序员拾山

MySQL

明道云零代码应用治理分层分级指南与量表

明道云

BSN祝全体技术工作者新春快乐!

BSN研习社

将混沌实验内建到持续交付过程中提升系统稳定性

QE_LAB

混沌工程 混沌测试 测试技术

扪心自问,我们在用户旅程的投入有多匮乏?

Yestodorrow

高效学 C++|函数参数的引用传递和函数重载

TiAmo

c++ 编程语言、

视觉大模型训练和推理加速

百度Geek说

人工智能 深度学习 transform 企业号 1 月 PK 榜

百度百舸 · AI 异构计算平台,加速自动驾驶模型迭代

百度Geek说

人工智能 自动驾驶 企业号 1 月 PK 榜

加速数字化转型,天翼云携手央国企积蓄发展新动能

天翼云开发者社区

音乐制作软件FL Studio21中文绿色版下载

茶色酒

FL Studio 21

到底卡在了哪里,2023年再撒谎网慢就说不过去了

Yestodorrow

架构 可观测性 网站性能

如何减少网站卡顿的代码级别详细文章

Yestodorrow

架构5作业

梁山伯

软件测试/测试开发丨免安装免配置环境的免费 ios 调试工具 sib 来啦

测试人

软件测试 自动化测试 测试开发 ios测试

培训学习前端开发技术好吗?

小谷哥

都用过@Autowired,但你知道它是怎么实现的吗

JAVA旭阳

Java spring

mathtype有免费的吗?如下下载最新版本

茶色酒

MathType2023

架构实战 - 模块 8 作业

mm

消息队列 架构实战营

第五周作业-微博评论高性能高可用的计算架构

不爱学习的程序猿

MySQL幻读到底是什么?怎么解决?

程序员拾山

MySQL

“天翼云杯”决赛收官!看看你pick的队伍战绩如何?

天翼云开发者社区

应用程序热补丁(三): 完整的设计与实现_文化 & 方法_王超_InfoQ精选文章