博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
强大的硬件虚拟化
阅读量:2344 次
发布时间:2019-05-10

本文共 3142 字,大约阅读时间需要 10 分钟。

一、vt核心vmcs

前几篇介绍了vt强大的无察觉劫持页表hook的能力,kvm的大致原理,但vt的能力远远不止于此。因为实现vt托管的操作系统,将可以做到指令级的管控。甚至直接基于vt形成调试器,如果用来调试内核,将会大大提高稳定性。整个vt核心全部位于vmcs的 状态域。根据intel 开发手册第三卷,控制域的核心部分分为1.guest field ,.2 host field , 3.vm-excution control field, 4.vm-Exit control field, 5.vm Entry control field, 6.vm-exit information fields, 7.VMCS types

这几部分我做简要介绍,有兴趣的自行查看intel 开发手册的详细介绍。

  1. guest field
    这一部分用来设置虚拟机状态,包括中断页表寄存器栈等信息,是vt运行的虚拟状态机,也就是虚拟机状态都在这个域中设置。
  2. host field
    这一部分是托管虚拟状态机的vmm(virtual machine manager),可以称为虚拟机管理器也要设置中断页表寄存器栈等信息,因为虚拟机在退出的时候将会由VMM来处理vm-exit的各种信息,实现对虚拟机的管控。
  3. vm-excution control field
    此域掌控non-root 模式下的操作,外部中断,NMI, 内部中断,cr3 cr8寄存器的读取和写入,无条件IO退出,MSR bitmaps,激活secondary control(虚拟APIC 访问, 是能EPT), exception Bitmap, VMCS指针, EPTP(Extended-Page-Table Pointer), VM-Funtion 控制(这个用来直接非根模式触发根模式定义的行为)
  4. vm-Exit control field
    这部分设置非根模式下的guest 触发定义行为后,进入根模式的VMM处理。
  5. vm Entry control field
    这部分设置根模式下的VMM 触发定义行为后,进入非根模式的guest。
  6. vm-exit information fields
    这部分自动记录vm-exit发生的原因,用来后续处理
  7. VMCS types
    区别原始VMCS和镜像VMCS的标识

二、虚拟机启动

基于开源ksm介绍。

在这里插入图片描述
启动部分,主要是vmcs的设置,位于ksm_init。必须每个cpu分别设置VMCS,以实现每个cpu的虚拟执行。这里在用户态注册了/dev/ksm用来操作vt. 代码实现了epage hook 页表劫持的hook, 用户态沙箱, 内视引擎,idt劫持等功能。
我介绍先前三个。有个很复杂的结构体ksm vcpu,发个缩略图吧。
ksm核心结构体

三、epage hook

首先普及下EPT, 为了更高效的实现GPA到HPA的转换,intel 设计了EPT机制,当然我自己理解这个转换其实不是必须的,因为单纯的GPA足够找到物理地址,这样设计的目的还是虚拟机管控的完整性,因为经我测试,取消ept的虚拟机照样可以运行。

在这里插入图片描述
总之这个过程其实和普通的页表查询很类似,但是实现从guest 物理地址到host物理地址的转换。

EPT页表的建立流程

  1. 初始情况下:Guest CR3指向的Guest物理页面为空页面;
  2. Guest页表缺页异常,KVM采用不处理Guest页表缺页的机制,不会导致VM Exit,由Guest的缺页异常处理函数负责分配一个Guest物理页面(GPA),将该页面物理地址回填,建立Guest页表结构;
  3. 完成该映射的过程需要将GPA翻译到HPA,此时该进程相应的EPT页表为空,产生EPT_VIOLATION,虚拟机退出到根模式下执行,由KVM捕获该异常,建立该GPA到HOST物理地址HPA的映射,完成一套EPT页表的建立,中断返回,切换到非根模式继续运行。
  4. VCPU的mmu查询下一级Guest页表,根据GVA的偏移产生一条新的GPA,Guest寻址该GPA对应页面,产生Guest缺页,不发生VM_Exit,由Guest系统的缺页处理函数捕获该异常,从Guest物理内存中选择一个空闲页,将该Guest物理地址GPA回填给Guest页表;
  5. 此时该GPA对应的EPT页表项不存在,发生EPT_VIOLATION,切换到根模式下,由KVM负责建立该GPA->HPA映射,再切换回非根模式;
  6. 如此往复,直到非根模式下GVA最后的偏移建立最后一级Guest页表,分配GPA,缺页异常退出到根模式建立最后一套EPT页表。
  7. 至此,一条GVA对应在真实物理内存单元中的内容,便可通过这一套二维页表结构获得。

有了ept的概念,我们知道,GPA到HPA有ept的一重映射,那么如果我们需要无察觉的hook内存,只需要GPA 映射到新的HPA,那么页表就可实现替换,并做一定的内存检查绕过。

ksm的实现架构如下:
epage hook
ept_alloc_page就是对ept映射的改变,也是hook的核心。作者定义了一些列eptp的指针,通过以下宏进行切换。

#define EPTP_EXHOOK			0			/* hook eptp index, executable hooks only  */#define EPTP_RWHOOK			1			/* hook eptp index, readwrite hooks, no exec  */#define EPTP_NORMAL			2			/* sane eptp index, no hooks  */#define EPTP_DEFAULT			EPTP_EXHOOK

原函数调用方式:

  • vcpu_vmfunc(EPTP_NORMAL, 0);
  • void *ret = MmMapIoSpace(x, y, z);
  • vcpu_vmfunc(EPTP_EXHOOK, 0);
  • return ret;

通过vmfunc实现根模式下的映射切换,便捷的实现页表切换。

四、用户态沙箱

图4.1

  1. 根据pid建立需要被隔离程序,struct sa_task。可以看到task->eptp有个初始化的过程,这个就是关键。
  2. 劫持cr vm->exit退出消息。
    图4.2
    vm_exit直接的可以获取的guest退出的类型,但是具体的退出信息还需要相应的状态域中读取。如图,vmcs_read(EXIT_QUALITICATION)获取到exit information后,通过解析域信息,获取到发生vm_exit的事件为mov to cr。然后获取寄存器号和寄存器值。这里的cr3值会被记录,如下图:
    图4.3
    之后就是访问控制,当发生特定进程的空间写操作的时候,触发ept violation:
    图4.4
    如上图4.4,沙箱会对写入的页表进行复制,写入独立的空间,实现进程隔离。

五、Introspect engine

这个引擎还是和ept相关,效果就是监控地址的访问。一旦发生特定地址的访问或执行,将会触发vm_exit,受到VMM的监控。

introspect engine架构
核心原理在于kms_instropct_add_watch, 通过addr->access设置访问属性,和addr->gpa访问地址。触发VMM
epte = ept_alloc_page(EPT4(ept, EPTP_DEFAULT), addr->access ^ EPT_ACCESS_ALL, mt, addr->gpa, addr->gpa);
那么ept的映射效果将是一旦在此地址发生访问或执行,VMM就可以接受到信息。从而监控特定地址的访问。

转载地址:http://gnjvb.baihongyu.com/

你可能感兴趣的文章
list排序
查看>>
搭建zookeeper集群
查看>>
1005. 数独
查看>>
1006. 求和游戏
查看>>
IDEA eclipse 控制台日志输出到文件
查看>>
1022. Fib数列
查看>>
一些开源项目
查看>>
将博客搬至CSDN
查看>>
MySQL 中事务的实现
查看>>
CheckStyle
查看>>
IDE配置jvm参数
查看>>
内存溢出
查看>>
Spring Cloud 声明式服务调用 Feign
查看>>
JVM实用参数(一)JVM类型以及编译器模式
查看>>
spring cloud config 属性加解密
查看>>
rabbitmq安装
查看>>
RabbitMQ 使用
查看>>
动态代理
查看>>
oracle中merge into用法解析
查看>>
MySQL Explain详解
查看>>