写点什么

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

  • 2017-04-20
  • 本文字数:4126 字

    阅读完需:约 14 分钟

前言

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

  • 修复运行时进程的函数
  • 加载热补丁到进程中
  • 自动生成热补丁等等

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

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

  • 热补丁的管理(加载、卸载、激活、回滚热补丁等)
  • 打入热补丁时的安全检查(简单说是什么时候打入热补丁是安全的)
  • 热补丁对多线程的支持等等。

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

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

UCloud 使用了内核热补丁修复了若干内核问题,避免了重启系统导致的服务中断,保证了操作系统本身的可用性。

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

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

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

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

设计理念提出需求

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

  • 应用程序热补丁的适用场景和内核热补丁是一致的,目的是修复缺陷,而不是增加功能和升级版本。所以应用程序热补丁必须允许函数级别上的修改(不论是本地函数还是全局函数)。
  • 应用程序热补丁必须是安全的,也就是打入热补丁的前后进程的状态必须一致,热补丁只会操作修改的函数,不会影响进程的正常运行。
  • 应用程序热补丁必须支持云平台环境中现代软件具有的特性,比如说 Linux x86_64、多线程等等。
  • 热补丁必须由工具来构建,也必须要由工具来管理(加载卸载等)。
  • 热补丁必须同时支持回滚,同时支持一个进程多次热补丁修复。
  • 降低热补丁运营的难度。

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

设计思路

  • 支持修复函数级别的、并且可以自动化生成热补丁的工具。
  • 支持多线程、热补丁安全检查、多热补丁状态管理的热补丁加载工具。
  • 运行中的应用程序应记录热补丁的信息和状态,可供外部工具查询。

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

框架组件

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

Creator

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

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

Loader

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

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

支持热补丁安全检查。

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

Core Runtime

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

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

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

热补丁(补丁本身)

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

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

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

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

实现方法

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

Creator

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

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

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

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

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/ 目录从内核中直接得到线程的信息。在停止所有线程之后,需要再次获取所有线程信息,查看是否有新增线程,如果有需要停止新增线程。重复以上动作直到没有新线程出现。

Core Runtime

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

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

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

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

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

如下所示:

热补丁(补丁本身)

这里的热补丁指的是狭义上的作为动态链接库被 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,我们利用应用程序热补丁修复了若干紧急安全漏洞和缺陷,在关键时刻迅速解决问题,相比于传统的软件升级方式,解决问题更加及时。

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


感谢孟夕对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们。

2017-04-20 19:003174

评论

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

Downie 4 for mac(视频下载工具) 4.6.32中文激活版

mac

视频下载工具 苹果mac Windows软件 Downie

如何找到靠谱的软件外包开发公司?

V\TG【ch3nguang】

区块链系统开发软件外包公司

V\TG【ch3nguang】

DAPP合约质押挖矿系统开发(源码搭建)

l8l259l3365

从零开始开发图床工具:使用 Gitee 和 Electron 实现上传、管理和分享

JYeontu

前端 Electron gitee 免费图床

Python 作用域:局部作用域、全局作用域和使用 global 关键字

小万哥

Python 程序员 软件 后端 开发

ES6新特性(三)

阡陌r

JavaScript ES6 Promise 迭代器 生成器

Linux touch命令:创建文件及修改文件时间

芯动大师

手机旗舰芯片巨头较量,都有哪些“秘密武器”?

脑极体

AI

鸿蒙生态伙伴赋能交流会·上海站举行,多项目签约开发元服务

最新动态

架构的边界感和架构师的超边界感

agnostic

架构边界

为什么人生必须被定义?去探索无限可能

少油少糖八分饱

梦想 探索与实践 人生修炼 突破瓶颈 自我价值

Python 模块:创建、导入和使用

小万哥

Python 程序员 软件 后端 开发

广州软件外包公司开发流程详解

V\TG【ch3nguang】

交易所开发 协议的力量:加密货币交易所开发中的技术选择

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 NFT开发 qukuail开发

AlDente Pro for Mac(电池最大充电限制软件)v1.22.3激活版

iMac小白

AlDente Pro AlDente Pro下载 AlDente Pro破解版 AlDente Pro mac

Java Web 框架对比,原来Webflux性能最差。

Kevin_913

Java springboot

2023-10-28:用go语言,给定一个n*m的二维矩阵,每个位置都是字符, U、D、L、R表示传送带的位置,会被传送到 : 上、下、左、右, . 、O分别表示空地、目标,一定只有一个目标点, 可以

福大大架构师每日一题

福大大架构师每日一题

Linux ln命令:建立链接文件

芯动大师

Linux cp命令:复制文件和目录

芯动大师

Illustrator 2023 for mac(ai2023矢量图形编辑软件) v27.9完整激活版

mac

ai2023 苹果mac Windows软件 矢量图形编辑软件 Illustrator 2023

重磅更新!Sermant 1.2.0 release版本新特性速览

华为云开源

云原生 字节码 无代理服务网格

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