libcareplus应用于Qemu-6.1.0

Posted rtoax

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了libcareplus应用于Qemu-6.1.0相关的知识,希望对你有一定的参考价值。

libcareplus应用于Qemu-6.1.0

荣涛
2021年9月26日

1. 环境与步骤

1.1. 软件版本

  • Qemu:6.1.0
  • libvirt:7.0.0
  • virt-manager:2.2.1

略过Qemu、libcirt、rit-manager以及虚拟机的安装,直接进行热补丁测试。

1.2. 测试步骤

  1. 使用virt-manager启动qemu-KVM虚拟机;
  2. 查看宿主机中的qemu进程,使用工具查看虚拟机Guest OS状态;
  3. 使用libcareplus制作补丁文件;
  4. 使用libcareplus生成补丁;
  5. 使用libcareplus加载热补丁;
  6. 使用libcareplus查看热补丁信息;
  7. 使用libcareplus删除补丁;

下面,按照上述步骤,进行分节详述。

2. 启动虚拟机

直接使用virt-manager启动或者使用virsh启动即可。

3. 查看宿主机中Guest OS进程

$ ps -ef | grep qemu-system
root       16961       1  0 Sep24 ?        00:18:59 /usr/bin/qemu-system-x86_64 -name guest=centos8, [省略参数...]

这是一个后台运行的进程,它的父进程是1号进程,在CentOS中为systemd进程,它的PID为16961

4. 创建补丁

可以参考视频教程《QEMU 用户态热补丁》中的实例,创建patch补丁文件。

首先,进入qemu目录,创建补丁文件0004.softmmu-qdev-monitor.patch

--- softmmu/qdev-monitor.c	2021-09-26 08:56:52.094677975 +0800
+++ patches/softmmu-qdev-monitor.c	2021-09-30 10:36:34.564842699 +0800
@@ -777,6 +777,7 @@ static void qbus_print(Monitor *mon, Bus
 
 void hmp_info_qtree(Monitor *mon, const QDict *qdict)
 {
+	qemu_printf("### hmp_info_qtree patched.\\n");
     if (sysbus_get_default())
         qbus_print(mon, sysbus_get_default(), 0);
 }

其中softmmu/qdev-monitor.cqemu-6.1.0源码路径,patches/softmmu-qdev-monitor.c为补丁源代码。这个补丁很简单,在函数起始处添加了一条打印,补丁文件可以使用diff -up src.c src-modify.c指令生成。

5. 编译源码生成二进制补丁

在测试阶段,此时没有虚拟机在运行,当准备好qemu的可执行文件后,再启动虚拟机。

使用libcareplus提供的脚本,对源码进行编译:

/home/rongtao/libcareplus/src/libcare-patch-make -j 10 --clean 0004.softmmu-qdev-monitor.patch

其中:

  • -j 10指定了参与编译的CPU核心数(该参数是我添加的,目前在gitee上提交了补丁,但是目前位置还没有被接受)
  • --clean表明此次编译是否需要删除上次编译的结果,即在编译前期是否执行make clean
  • 0004.softmmu-qdev-monitor.patch为补丁的文本文件;

在编译过程中,会将gcc重定向到libcare-cc中,不过不用担心,这已经在脚本libcare-patch-make中帮你做了。还会生成补丁对应的汇编文件,并利用此汇编文件生成ELF文件,并通过一层封装生成二进制补丁文件。

在我们的是过程中,我们将补丁重命名为mypatch1.kpatch

6. 启动虚拟机

使用virt-manager或者virsh启动虚拟机

# virsh list
 Id   Name      State
-------------------------
 5    centos8   running

此时,qemu进程已经正常运行:

# ps -ef | grep qemu
root       53108       1  2 11:13 ?        00:00:23 /usr/bin/qemu-system-x86_64 [...]

需要注意的是,我的测试环境只有一个虚拟机运行,如果存在多个虚拟机,同时会存在qemu进程。

7. 加载热补丁

为了验证热补丁的加载是否成功,这里先进行反汇编查看打补丁位置的汇编代码:

# gdb -q -p $(pidof qemu-system-x86_64)
Attaching to process 53108
[New LWP 53114]
[New LWP 53119]
[New LWP 53120]
[New LWP 53122]
[New LWP 53123]
[...]

因为现在gdb attach了qemu进程,所以你会从virt-manager中看到,虚拟机停止运行了:

这时候,在gdb的命令行下,反汇编我们打补丁的函数hmp_info_qtree

(gdb) disassemble hmp_info_qtree
Dump of assembler code for function hmp_info_qtree:
   0x000055d20a164ea0 <+0>:	push   %rbx
   0x000055d20a164ea1 <+1>:	mov    %rdi,%rbx
   0x000055d20a164ea4 <+4>:	callq  0x55d20a1aa1b0 <sysbus_get_default>
   0x000055d20a164ea9 <+9>:	test   %rax,%rax
   0x000055d20a164eac <+12>:	je     0x55d20a164ec8 <hmp_info_qtree+40>
   0x000055d20a164eae <+14>:	callq  0x55d20a1aa1b0 <sysbus_get_default>
   0x000055d20a164eb3 <+19>:	mov    %rbx,%rdi
   0x000055d20a164eb6 <+22>:	xor    %edx,%edx
   0x000055d20a164eb8 <+24>:	pop    %rbx
   0x000055d20a164eb9 <+25>:	mov    %rax,%rsi
   0x000055d20a164ebc <+28>:	jmpq   0x55d20a163be0 <qbus_print>
   0x000055d20a164ec1 <+33>:	nopl   0x0(%rax)
   0x000055d20a164ec8 <+40>:	pop    %rbx
   0x000055d20a164ec9 <+41>:	retq   
End of assembler dump.

然后,我们退出gdb,这将会使qemu进程(KVM虚拟机)继续运行。

下面进行热补丁的加载:

# /home/rongtao/libcareplus/src/libcare-ctl patch -p $(pidof qemu-system-x86_64) mypatch1.kpatch
1 patch hunk(s) have been successfully applied to PID '53108'

再次进行gdb反汇编:

(gdb) disassemble hmp_info_qtree
Dump of assembler code for function hmp_info_qtree:
   0x000055d20a164ea0 <+0>:	jmpq   0x55d20ac475f0
   0x000055d20a164ea5 <+5>:	(bad)  
   0x000055d20a164ea6 <+6>:	push   %rbx
   0x000055d20a164ea7 <+7>:	add    $0x0,%al
   0x000055d20a164ea9 <+9>:	test   %rax,%rax
   0x000055d20a164eac <+12>:	je     0x55d20a164ec8 <hmp_info_qtree+40>
   0x000055d20a164eae <+14>:	callq  0x55d20a1aa1b0 <sysbus_get_default>
   0x000055d20a164eb3 <+19>:	mov    %rbx,%rdi
   0x000055d20a164eb6 <+22>:	xor    %edx,%edx
   0x000055d20a164eb8 <+24>:	pop    %rbx
   0x000055d20a164eb9 <+25>:	mov    %rax,%rsi
   0x000055d20a164ebc <+28>:	jmpq   0x55d20a163be0 <qbus_print>
   0x000055d20a164ec1 <+33>:	nopl   0x0(%rax)
   0x000055d20a164ec8 <+40>:	pop    %rbx
   0x000055d20a164ec9 <+41>:	retq   
End of assembler dump.

很显然,函数开头的汇编指令push %rbx被替换为jmpq 0x55d20ac475f0,热补丁成功。

8. 删除热补丁

直接执行删除的命令即可

# /home/rongtao/libcareplus/src/libcare-ctl unpatch -p $(pidof qemu-system-x86_64)
1 patch hunk(s) were successfully cancelled from PID '53108'

如果使用gdb再次进行反汇编,会发现函数起始的指令又被替换回push %rbx指令。


Copyright (C) CESTC Com.

以上是关于libcareplus应用于Qemu-6.1.0的主要内容,如果未能解决你的问题,请参考以下文章

Qemu-6.1.0多热补丁管理

LibcarePlus用户态程序热补丁

安装Qemu-6.1.0

libcareplus多补丁管理

libcareplus支持的补丁类型

用户态热补丁