NVIDIA 初创加速计划,免费加速您的创业启动 了解详情
写点什么

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

  • 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:002918

评论

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

重磅 | 青藤蜂巢入围领导者象限,增长指数&综合竞争力第一!

青藤云安全

主机安全 青藤云安全

聚焦云计算、大数据、人工智能等开源技术,这场开源开发者的盛会不容错过!

开源社

#开源 COSCon'22 2022 第七届中国开源年会

整个汽车产业链,都能“挤上”这朵云?

脑极体

“程”风破浪的开发者|从一大堆杂事中要效率

架构精进之路

学习方法 提升效率 “程”风破浪的开发者

官宣:新功能正式上线!

青藤云安全

主机安全 青藤云安全 青藤智库

Apache Kyuubi 在B站大数据场景下的应用实践

网易数帆

hive Kyuubi spark SQL 企业号十月 PK 榜

Spring之定时调度

Andy

华为云桌面,随时随地助力企业轻松办公

科技怪授

华为云桌面

Spring之资源读取

Andy

华为云桌面,如何为企业构建新型工作方式

爱科技的水月

一个疯子居然获得北京市科学技术奖?

青藤云安全

青藤云安全 北京科学技术奖

云原生机甲,真正的服务网格

如水

云原生 servicemesh 云原生机甲 CloudMecha

【web 开发基础】PHP 的流程控制之多向条件分支结构(switch) -PHP 快速入门 (16)

迷彩

switch case switch语句 10月月更 PHP基础 分支结构

数组元素积的符号

掘金安东尼

算法 10月月更

企业办公转型的出路在哪里?华为云桌面开创办公新形式

爱科技的水月

华为云弹性云服务器助力打造更安全可靠、灵活高效的云空间

爱尚科技

华为云连接CC,助力企业一站式解决跨区域传输难问题

科技怪授

华为云CC链接

跨区域传输数据不够流畅?华为云连接CC了解一下

科技怪授

华为云链接

Spring之依赖注入

Andy

华为云安全性、可靠性、资源、创新性跻身行业前列

爱尚科技

万物皆可集成系列:低代码对接阿里物流API实现快递跟踪

葡萄城技术团队

前端 低代码 电商 API

“程”风破浪的开发者 | web3.0爆红是炒作还是真有赚头?

三掌柜

Web3.0 10月月更 “程”风破浪的开发者

公共 IP 地址和私有 IP 地址有什么区别?

wljslmz

IP地址 网络技术 10月月更 公网ip 私网ip

禅道项目管理软件功能、价格,及使用指南

PingCode

“程”风破浪的开发者|satoken实现优雅鉴权

codingyt

学习方法 安全 鉴权 10月月更 “程”风破浪的开发者

低代码在企业数字化转型中有什么价值?

SoFlu软件机器人

Apache IoTDB v0.13.3 发布!

Apache IoTDB

数据库 Apache IoTDB

Spring Boot「17」数据库连接池

Samson

Java spring 学习笔记 spring-boot 10月月更

宝藏级别,GitHub上的SpringBoot核心笔记,讲得太清晰了

程序知音

云上作业就是这么轻松,华为云桌面的工作新体验

爱科技的水月

政企办公新入口,华为云桌面安全便捷更高效!

爱科技的水月

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