基于VMI的Linux虚拟机系统调用解析
VMI(Virtual Machine Introspection,虚拟机自省),是一种从虚拟机外部对虚拟机内部状态进行监控的技术。基于VMI获取的内存数据并结合通过KVM对VCPU相关信息的获取,实现将该类低级语义转换为系统调用层面的高级语义信息,从而可以一定程度的分析出系统的行为。 有关基于KVM的VMI开发环境部署可参考这篇文章。本文主要记录有关修改KVM源码实现系统调用陷入、对内存数据进行语义转换相关的原理与流程。 Kernel Side-获取系统调用的寄存器信息 在KVM侧主要实现的是设置VCPU的陷入以及一些VCPU基本信息的获取,如VM的VCPU数量、VM相关的一些句柄等等。除去设置陷入需要对VCPU的状态进行修改,其他的接口通过ioctl的方式来提供给用户态。 Intel x86 VMX架构简介 Intel 为了实现CPU的硬件虚拟化,在原来x86 CPU的基础上增加了VMX(Virtual Machine Extensions)架构。在VMX架构中有两类软件,这也是现今虚拟化的基本模式,分别是虚拟机监控器(VMM,就是KVM、Xen这类软件)和虚拟机(VM)。VMM对于整个系统的硬件资源具有完全的掌控权,然后再将机器的实体硬件进行抽象和模拟,最终提供给运行于其上的虚拟机。除了给虚拟机提供虚拟的硬件资源之外,VMM还负责保证不同虚拟机实例之间的互相隔离与独立,并且确保每个虚拟机在资源使用、调度等方面都是公平的。 但是传统的操作系统内核都是运行在CPU的Ring 0特权级别(定义参见Protection ring - Wikipedia),而为了完全掌控虚拟机的硬件,虚拟机的系统内核显然不能直接运行在Ring 0,所以为此Intel引入了一种新的CPU操作VMX operation(具体介绍在Intel SDM Volume 3, Chapter 23),来支撑虚拟机的运行。VMX Operation包含两类CPU操作: VMX root operation:VMM运行在该种操作模式下,CPU行为和VMX operation之外的行为相似; VMX non-root operation:VM运行在该种操作模式下,CPU的一些指令操作受限。 两种操作模式下,均有独立的Ring 0-Ring 3的特权级别,VMX operation和CPU特权级别是正交的,且两种操作模式可以相互转换,称为VMX转换(VMX transition)。VMX root转换为VMX non-root称为VM Entry,VMX non-root转换为VMX root称为VM Exit。 通过VM Entry,可以令一个虚拟机进入到运行状态,而当虚拟机在执行某些特殊指令的时候也会产生VM Exit退出到VMM,从而交由VMM处理。为了支撑这样一种模式的正常运行,Intel也设计了一系列指令,并且对每个虚拟机都提供了一个对应的控制数据结构,称为VMCS(Virtual Machine Control Structure),用于存储虚拟机的相关信息。指令的详细描述,可见Intel SDM Volume 1 Chapter 5.22。 令虚拟机陷入KVM 为了在VMM的层面上监控系统调用的信息,很容易想到就是让虚拟机在每当产生系统调用的时候就产生VM Exit,陷入到VMM,再对其CPU、寄存器等信息进行获取,以便后续处理。根据发起系统调用的方式不同分为以下三类,但是其基本原理都是产生一个系统中断,从而陷入到VMM中(KVM只能捕获系统中断): 基于中断的系统调用 对于一些老版本的OS,系统调用通过用户中断的方式来进行实现(如Linux为int 0x80,Windows为int 0x2e),所以可以通过修改中断描述符表(IDT),将所有用户中断描述符全部删除,只保留系统中断描述符,之后每当发起用户中断时,都会因为查询IDT地址越界产生一个#GP异常(General Protection Fault),引起系统中断。 ...