Page 327 - 《软件学报》2021年第10期
P. 327

陈兴蜀  等:VMOffset:虚拟机自省中一种语义重构改进方法                                                3299


                                   Table 1    Related description of process offset acquisition algorithm
                                              表 1   进程偏移量获取算法相关说明
                               变量/函数名                             说明
                             candi_offset_list   该变量为链表,链表中包含该特定成员的所有偏移量候选项
                             get_ts_addr()   该函数用于获取 TVM 中当前进程描述符的起始地址,具体见第 2.2.1 节
                             read_addr()   该函数用于读取 TVM 中某地址处的具体内容,具体见第 2.2.2 节
                             check_condition()   该函数用于判断相关内存内容是否满足制定的约束条件,具体见第 2.2.3 节
                    图 4 中:
                       第 1 行~第 4 行首先依据待获取偏移量的成员类型得到其偏移量的所有候选项,即 XF Candi_init .以 pid 为
                        例,Linux 使用 4 字节的 int 类型存储进程的 pid,根据结构体的字节对齐原则可知,成员 pid 相对于
                        task_struct 结构体起始地址的偏移量必须是 4 的倍数,故设置其 specific_size 为 4.需注意的是:TVM 内
                        核源码可能会被修改,因此从 0 开始到 task_struct 结构体大小的范围内,每增加 specific_size 的值均可
                        能为 pid 成员的偏移量,将这些值均作为成员 pid 的偏移量候选项添加至集合中;
                       第 5 行~第 13 行则对所有候选项进行筛选,得到最终偏移量.其中,第 6 行~第 11 行为一次偏移量获取
                        的流程.
                            第 6 行根据陷入时刻 TVM 的寄存器信息获取当前进程结构体的首地址;
                            第 7 行~第 11 行则对集合中的每个偏移量候选项,首先获取该地址处的内存内容,然后以基于该
                             成员属性制定的约束条件为依据,判断其内容是否满足约束条件:若不满足,则将该候选项从集
                             合中删除.
                        第 1 次执行偏移量获取流程时,XF Candi_prev 即为 XF Candi_init ,依照条件删除 XF Candi_not 后,可得 XF Candi_after .
                        由于对不同进程实例而言,其相同成员的偏移量是不变的,因此,当 TVM 中不同进程实例因产生指定
                        监控事件陷入到 VMM 中时,VMOffset 均可以上一次得到的 XF Candi_after 为此次获取流程的 XF Candi_prev ,
                        执行第 6 行~第 11 行的偏移量获取流程,删除此次内存状态不满足约束条件的 XF Candi_not 集合,得到新
                        的 XF Candi_after .迭代地执行此过程,直到对应集合中仅有一个成员,此时说明已成功获取该结构体成员
                        的偏移量,将其输出.
                    在 TVM 启动过程中,对某特定成员而言,TVM 中各个进程实例在该成员的各个候选偏移量处的内存内容
                 是动态变化的,其内存内容包括满足和不满足所制定约束条件两种可能.将候选偏移量处内存内容满足约束条
                 件的事件表示为 T,以 P T 表示事件 T 发生的概率.可知:对某成员唯一正确的偏移量而言,其内存内容会始终满足
                 基于其自身制定的约束条件,故其 P T 始终为 1;而对该成员的其他候选偏移量而言,其内存内容则会逐渐表现出
                 该处成员自身特性,而非约束条件所属成员特性,因此,其 P T 小于 1.若事件 T 发生的概率 P T 等于 1,则 n 次迭代
                                            n
                 过程中事件 T 一直发生的概率(P T ) 也始终为 1,即正确的偏移量在迭代过程中会始终保留不被删除.由公式(3)
                                                                                   n
                 可知:当事件 T 发生的概率 P T 小于 1 时,n 次迭代过程中事件 T 一直发生的概率(P T ) 会逐渐减小至接近 0:
                                                   lim( )P  n    0,0   P   1                       (3)
                                                   n  T       T
                    一般而言,TVM 启动过程中调用 do_fork()及 release_task()的次数超过 1 000 次.因此,随着上述过程迭代次
                 数的增加,不符合约束条件的候选偏移量会被逐渐删除,最终得到唯一正确的偏移量.
                 2.2.1    获取进程描述符起始地址
                    如图 5 所示,Linux 内核中,默认情况下内核栈占据两个连续的物理页面,即 8KB.内核栈由高地址向低地址
                 增长,8KB 地址区间的起始位置保存着线程描述符 thread_info.当 TVM中进程因调用 do_fork()及 release_task()
                 陷入至 VMM 时,TVM ESP 寄存器指向内核栈的栈顶单元,通过屏蔽栈顶地址的低 13 位,可获取线程描述符
                 thread_info 结构体的首地址,其第 1 个成员 task 指向当前进程的进程描述符 task_struct,故可基于此获取进程描
                 述符 task_struct 结构体的起始地址.
   322   323   324   325   326   327   328   329   330   331   332