openEuler 的操作系统热补丁探究实验
openEuler 的操作系统热补丁探究实验
一、 实验目的
- 了解操作系统热补丁:掌握什么是操作系统热补丁。
- 学会使用openEuler 的操作系统热补丁:学会安装并使用 SysCare,即 openEuler 的操作系统热补丁服务。
二、 实验环境
- 宿主机:Windows 10/11 或 macOS
- 虚拟机软件:VMware Workstation
- 目标系统:openEuler 22.03 LTS 或 24.03 LTS (x86_64 架构)
- 开发工具:VS Code
三、 实验内容与步骤
1 操作系统热补丁
1.1 什么是操作系统热补丁
操作系统热补丁(Operating System Hot Patching),在 Linux 领域常被称为 Kernel Live Patching (KLP),是一种在不重启系统的情况下,动态修复操作系统内核或关键服务漏洞的技术。
1.2 为什么要用热补丁?
通常,操作系统内核(Kernel)出现严重安全漏洞(比如提权漏洞、缓冲区溢出)时,标准的修复流程是:
- 下载新内核。
- 安装新内核。
- 重启服务器 (Reboot)。
痛点在于“重启”:
- 业务中断:数据库、Web 服务、AI 训练任务会被强制中断。
- 维护窗口难协调:对于 7x24 小时运行的系统(如双十一期间的淘宝服务器、证券交易系统),很难找到时间重启。
- 状态丢失:内存中的缓存数据(Cache)会丢失,重启后系统需要预热,性能会抖动。
热补丁的价值:零停机(Zero Downtime)。你可以在用户毫无感知的情况下,修复高危漏洞。
1.3 操作系统热补丁是如何实现的?
热补丁的核心技术原理通常涉及 “函数重定向(Function Redirection)” 或 “跳板(Trampoline)” 机制。
以 Linux 内核为例,过程大致如下:
1. 准备阶段
开发者发现内核函数 vulnerable_func() 有 Bug,于是写了一个修复后的新函数 patched_func()。编译器将这个新函数编译成二进制机器码。
2. 加载阶段
通过内核模块(Kernel Module, .ko)将包含 patched_func() 的代码加载到内核内存中。
3. 替换阶段
热补丁工具会找到内存中旧函数 vulnerable_func() 的入口地址。
它会利用 CPU 的指令,将旧函数的第一条指令(Prolog)修改为一条 跳转指令(JMP / ftrace call)。
-
修改前:
vulnerable_func: push rbp <-- 这是第一条指令 mov rbp, rsp ... (有 Bug 的代码) ... -
修改后(热补丁生效瞬间):
vulnerable_func: jmp patched_func <-- 被强行改为跳转到新函数 mov rbp, rsp <-- 后面的代码永远不会被执行到了 ...
4. 执行阶段
当操作系统或其他进程再次调用 vulnerable_func() 时,CPU 刚读到第一行,就被“踢”到了 patched_func() 里去执行。执行完新函数后,直接返回调用者。
结果:旧代码虽然还在内存里,但实际上已经被“架空”了。
三、 操作系统热补丁的局限性
虽然听起来很完美,但热补丁不能修复所有问题。它的技术限制非常大:
-
不能修改数据结构(Data Structure):
如果你想修复的 Bug 需要给某个struct task_struct增加一个字段(比如加个int id),热补丁通常做不到。因为内存里已经存在的成千上万个旧结构体是没有这个字段的,代码一旦访问就会内存越界(Crash)。- 结论:热补丁通常只能改逻辑(代码),不能改结构(数据)。
-
函数签名限制:
如果新函数的参数个数、类型发生了剧烈变化,或者涉及复杂的栈操作,热补丁极其难以实现。 -
性能损耗:
虽然很小,但多了一次跳转指令(JMP/Trampoline),在极度高频调用的函数上可能会有纳秒级的性能损耗。
四、 主流实现方案
在业界,不同的厂商有不同的实现:
-
kpatch (Red Hat):
基于 ftrace 机制。它通过生成二进制差异(binary diff),暂停内核执行(stop_machine),替换函数,然后恢复。这是 RHEL/CentOS 的标准方案。 -
kGraft (SUSE):
主打“懒加载”。它不强制暂停所有 CPU,而是等待进程自己“慢慢切换”到新代码。 -
Livepatch (Canonical/Ubuntu):
基于上游 Linux 内核的通用 Live Patching 框架,结合了 kpatch 和 kGraft 的优点。 -
Windows Hotpatching:
微软在 Azure 和 Windows Server 2022 引入的功能。它要求代码在编译时就预留好“空位”(Padding),方便后续填入跳转指令。
2 openEuler 的操作系统热补丁(SysCare)
2.1 认识 SysCare
一、简介
SysCare是一个操作系统热补丁服务,统一了操作系统内核态、用户态热补丁服务。为操作系统提供在线的热补丁修复能力,可以自动化、无感知地在线修复内核、用户态服务、动态库等系统基础组件bug和漏洞。

二、SysCare 系统功能
SysCare提供补丁制作、补丁激活和补丁卸载等功能,支持内核热补丁、用户态热补丁制作和管理:
-
一键式补丁制作能力:
- 目前SysCare统一内核热补丁和用户态热补丁的制作流程,提供一键制作补丁能力,对用户屏蔽制作补丁细节及用户态、内核态补丁制作差异。
-
补丁安装、激活、卸载:
- SysCare提供统一补丁管理接口,方便用户在补丁安装、激活、卸载查询使用。
三、SysCare 系统技术
- SysCare归一化补丁制作,对用户屏蔽补丁制作的细节及差异,提供统一的补丁管理工具,提升运维效率。
- SysCare提供的用户态热补丁支持用户态多进程/多线程业务热修复,修复简单、提升运维效率;对进程/线程新拉起、重启均生效。
- 热补丁lazy机制,克服ptrace缺陷(需全部退出内核调用),提升修复成功率。
2.2 安装 SysCare
-
挂载镜像
mount /dev/sr0 /mnt -
SysCare在编译前需要安装依赖包,相关命令如下:
sudo dnf install cmake make rust cargo kernel-devel elfutils-libelf-devel llvm clang bpftool libbpf libbpf-devel libbpf-static -
下载 git
sudo dnf install -y git -
源码编译安装SysCare
git clone https://gitee.com/openeuler/syscare.git cd syscare mkdir build cd build cmake -DCMAKE_INSTALL_PREFIX=/usr -DKERNEL_VERSION=$(uname -r) .. make make install
2.3 热补丁制作
用户可以使用sycare build命令制作热补丁,该命令为纯CLI工具,提供从RPM包生成热补丁包的功能,热补丁包以RPM包的形式封装维护,支持制作内核热补丁及用户态热补丁。
-
准备热补丁目标软件 zlib 的源码包(source rpm)及软件调试信息包(debuginfo rpm)
# 下载 zlib 的源码包和调试包 dnf download --source zlib dnf download zlib-debuginfo -
编写用户态补丁 zlib_lab.patch
补丁的作用是把 zlib 的版本名加上 " -Syscare-Lab-Success"
# 查看 zlib 版本 dnf list installed zlib # 把 1.2.13 替换成你自己的版本 cat << EOF > zlib_lab.patch --- a/zutil.c +++ b/zutil.c @@ -28,7 +28,7 @@ const char * ZEXPORT zlibVersion() { - return ZLIB_VERSION; + return "1.2.13-Syscare-Lab-Success"; } #endif -
编写测试程序 test_zlib.c
cat << EOF > test_zlib.c #include <stdio.h> #include <zlib.h> #include <unistd.h> int main() { while(1) { printf("当前 zlib 版本: %s\n", zlibVersion()); sleep(2); // 每2秒打印一次,方便观察动态替换 } return 0; } EOF # 编译并运行测试程序(后台运行) gcc test_zlib.c -o test_zlib -lz ./test_zlib
可以看到当前版本为 1.2.13
-
执行 syscare build 命令构建热补丁
syscare build \ --patch-name HP_ZLIB \ --source zlib-*.src.rpm \ --debuginfo zlib-debuginfo-*.rpm \ --patch zlib_lab.patch \ --output output
2.4 热补丁的管理
-
热补丁包安装
dnf install output/patch-zlib-*.rpm -y -
查询所有补丁状态
syscare list
-
加载热补丁
# name 替换成之前查询到的补丁名字 syscare apply zlib-1.2.13-4.oe2403sp2/HP_ZLIB-1-1/libz.so.1.2.13
可以看到程序没有重新运行,但是 zlib 的版本变了,代表热补丁加载成功。
-
卸载热补丁
# name 替换成之前查询到的补丁名字 syscare remove zlib-1.2.13-4.oe2403sp2/HP_ZLIB-1-1/libz.so.1.2.13
卸载热补丁后 zlib 版本又变回 1.2.13
-
热补丁包卸载
dnf remove output/patch-zlib-* -
关闭程序
# 查找进程 ps -ef | grep test_zlib #删除进程 pkill test_zlib
*思考题:
1. 原理理解:函数重定向
在实验的理论部分提到,热补丁通过将旧函数的入口地址修改为一条“跳转指令(JMP)”来实现修复。请思考:
- 在执行
syscare apply后,原有的旧代码是否从内存中消失了? - 如果旧函数正在被某个线程执行(即处于运行栈中),此时打入热补丁是否会立刻引发崩溃?(提示:了解 SysCare 的 lazy 机制)。
2. 关键素材:Debuginfo 的作用
在实验 2.3 节中,我们除了下载源码包,还专门下载了 zlib-debuginfo。
- 为什么在“制作”热补丁时必须使用调试信息包?
- 如果我们在一个内核版本为
6.6.0-1的系统上,使用6.6.0-2版本的 Debuginfo 制作补丁,可能会发生什么后果?
3. 运维场景:热补丁 vs. 冷补丁
对比传统的 dnf update 修复漏洞(冷补丁/冷更新)与使用 syscare(热补丁),请从以下三个维度总结热补丁的优势与挑战:
- 业务连续性(系统是否需要重启)
- 素材准备(操作复杂程度)
- 生效范围(是仅对当前运行进程有效,还是对重启后的进程也有效)
4. 实验现象观察
在 2.4 节激活补丁时,观察 test_zlib 程序的输出:
- 程序在版本号从
1.2.13变为1.2.13-Syscare-Lab-Success的瞬间,进程 ID (PID) 是否发生了变化? - 这一现象说明了热补丁与普通重启服务的本质区别是什么?
- 点赞
- 收藏
- 关注作者




评论(0)