当前位置: 首页 > 工具软件 > CRIU > 使用案例 >

CRIU内核补丁分析

步衡
2023-12-01

1. 将procfs的proc_get_link中使用的inode传参改为dentry传参

2. 在procfs添加/proc/pid/map_files/目录用于建立本进程到其所用动态库、进程的二进制文件的软链接,以文件在内存映射的VA地址段即文件名

2.1 当dump一个进程的映射的时候,需要确切的知道其所用的二进制/动态库文件的映射地址,添加了map_files目录可以直接拿到这些映射

2.2 用map_files做对比,也可以确定出此进程共享的匿名映射

2.3 当restore一系列进程,这些进程还有共享映射的时候,我们给第一个进程做映射,然后再按照第一个进程的映射给第二个进程做映射

2.4 /proc/pid/maps文件也有进程地址映射的信息,但是需要重复的读取、解析,影响restore效率

3. 在prctl添加PR_SET_MM来允许用户态修改进程的mm_struct

当恢复一个进程的时候,我们需要从用户态将进程的代码段、数据段、数据堆的大小,配置成checkpoint时的值,因此需要添加PR_SET_MM。要修改的mm_struct中的数值大多数是统计性质的,用来计算/proc/pid/statm,但是start_brk和brk则是用来计算程序能够将数据段扩展到多大,修改这些值是危险的,因此需要在prctl中检查:进程是否具有CAP_SYS_RESOURCE权限(一开始是查ADMIN,但后来觉着啥都查ADMIN不合适);对于除了start_brk/brk以外的操作,都是需要存在VMA支持的,并且VMA flag必须符合-代码段可执行但不可修改,数据段不可执行;start_brk/brk值必须不能与数据段交叉,且不可超出RLIMIT_DATA。最后,编内核时还要打开CONFIG_CHECKPOINT_RESTORE。

mm_struct中start_code/end_code是程序代码段的起始/结束地址;start_data/end_data是程序data+bss段的起始/结束地址;start_brk是heap内存可以brk()扩展的起始地址,都放在/proc/pid/stat。

4. 在sysctl添加了可对当前进程pid namespace的last_pid元素的读写

5. 添加/proc/pid/task/tid/children文件,用于输出子进程列表

做checkpoint时,需要知道子进程的列表,获取进程的parent是容易的,/proc/pid/status中的PPid即可得到,但是要获取子进程列表,需要遍历所有pid,因此添加/proc/pid/task/tid/children,利用seq_file操作函数(seq_file操作函数会循环执行注册的回调函数start/show/next,直至next返回空),利用task_struct中children和sibling元素,遍历输出所有子进程。

6. 在/proc/pid/stat添加arg_start/arg_end(进程参数所在的地址段)/env_start/env_end(进程环境变量所在地址段)/exit_code(进程退出码,处理僵尸进程)信息,以方便checkpoint读取。并在prctl添加PR_SET_MM_(ARG_START|ARG_END|ENV_START|ENV_END|AUXV)可以在restore的时候能恢复程序的启动参数和环境变量以及saved_auxv。再加上之前已经有的,最终需要配置的有PR_SET_MM_(START_CODE|END_CODE|START_DATA|END_DATA|START_STACK|START_BRK|BRK)

7. 添加kcmp() syscall来做两个进程是否共享内核对象

在用户态做checkpoint-restore需要决定mm_struct/file_struct等是否在多个task间共享,是否恢复其状态。决定是否恢复其状态可以通过创建进程时的CLONE_flag来控制;但是确定是否有多个task共享由于直接在proc文件里加mm_struct ID会存在安全问题,就需要添加一个比较用的syscall,kcmp(),在内核中进行比较,然后返回比较结果。

8. 在prctl()添加修改mm_struct::exe_file的能力

在restore的时候,需要将mm_struct::exe_file修改为进程checkpoint时的二进制文件,如此/proc/pid/exe才能正确的指出二进制文件。添加PR_SET_MM_EXE_FILE,然后传入文件描述符,然后即可以修改;另外,exe_file仅可修改一次,如果mm::num_exe_file_vmas(可执行的vma数量)超过0或exe_file已有指向,则不可修改,不过后来2020年有个补丁干掉了num_exe_file_vmas,exe_file也不再准确,改为“遍历vma并查看是否存在vma映射了文件,若存在则不能将exe_file修改成未映射过的二进制文件;在mm::flags添加MMF_EXE_FILE_CHANGED标志位,指示exe_file是否发生过修改”。

9. prctl()添加获取clear_tid_address的能力

线程退出(pthread_join)会在clear_tid_address写0,有sys_set_tid_address可以修改clear_tid_address,但是却没有接口能允许从用户态获取它的值。不能获取这个值,则不能支持有pthread_join调用的程序restore,最终给prctl添加PR_GET_TID_ADDRESS获取这个值。

10.

 类似资料: