软件学报  2014, Vol. 25 Issue (10): 2235-2250   PDF    
VM内部隔离驱动程序的可靠性架构
郑豪1, 董小社1, 王恩东2, 陈宝可1, 朱正东1    
1. 西安交通大学 计算机科学与技术系, 陕西 西安 710049;
2. 高效能服务器和存储技术国家重点实验室, 山东 济南 250013
摘要:利用虚拟化技术来整合资源已成为高性能服务器提高资源利用率的重要手段,虚拟化技术的可靠性对于高性能服务器所提供服务的质量至关重要.然而,驱动故障严重影响了虚拟机中操作系统的可靠性,也同样影响到整个服务器的可靠性.为此,提出一种在虚拟机内部通过隔离故障驱动程序来提高虚拟机可靠性的架构,该架构通过监视驱动程序所使用的内存信息来建立驱动可写权限的授权表,并在虚拟机监视器中设置虚拟机内核空间对应影子页表的写保护来捕获虚拟机的写操作,进而结合授权表判断被隔离驱动程序写操作的正确性.目前,该架构能够在无需修改驱动程序的情况下,在虚拟机内部实现对驱动程序的隔离.实验结果表明:该架构可以隔离84.63%的注入故障造成的系统崩溃失效,并且对于驱动性能的影响小于20%,提高了虚拟化环境的可靠性.
关键词虚拟化     可靠性     驱动隔离    
Reliability Architecture to Isolate the Driver Inside the VM
ZHENG Hao1, DONG Xiao-She1, WANG En-Dong2, CHEN Bao-Ke1, ZHU Zheng-Dong1    
1. Department of Computer Science and Technology, Xi'an Jiaotong University, Xi'an 710049, China;
2. State Key Laboratory of High-End Server & Storage Technology, Ji'nan 250013, China
Corresponding author: ZHU Zheng-Dong, E-mail: zdzhu@mail.xjtu.edu.cn
Abstract: Using virtualization technology to integrate resources has become an important mean to improve the resource utilization of current high-performance servers. Thus the reliability of virtualization technology is very crucial to the service quality of high- performance server. However, the driver fault greatly impacts not only the reliability of operating system inside the virtual machine but also the reliability of the servers. In light of issue, this paper presents a driver isolation architecture inside the virtual machine to improve its reliability. It establishes the authorization table by monitoring the memory information which are used by the driver, captures the driver's write operations by setting the write protection of the shadow page table corresponding to the kernel space of the virtual machine, and judges the correctness of write operations of the isolated driver with the authorization table. Currently, the architecture can isolate drivers inside the virtual machine without modifying them. Experimental results show that the architecture can isolate 84.63% injection faults which cause system crashes with the performance loss less than 20%, and therefore effectively improves the reliability of the virtualization environment.
Key words: virtualization     reliability     driver isolation    

当前,高性能服务器常常通过虚拟化技术为更多的用户提供服务,以提高服务器资源的利用率.用户可以重用已有的操作系统和应用程序来定制自己的虚拟机(VM)环境,对于不同的VM,都认为它拥有整个系统的所有资源,而且VM之间具有相互隔离性.然而在VM内部,占操作系统代码比重最大、由第三方开发、缺乏完善测试的驱动程序所存在的可靠性问题[1, 2, 3]严重影响着VM内操作系统的可靠性.考虑到驱动程序故障大多为瞬时故障[4],如果存在一种在VM内部实现对故障驱动进行隔离的架构,就可以提高VM内操作系统的可靠性.同时,由于已有驱动程序数量庞大,驱动隔离架构需确保对驱动程序的兼容性,即:在不修改驱动程序的情况下,防止VM内部驱动程序故障引起整个VM内核的崩溃,从而提高VM服务的可靠性.

由于VM本身具有隔离特性,当前存在多种利用虚拟化技术的隔离性[5, 6, 7, 8]来提高操作系统可靠性的方法.虽然这些方法利用了虚拟化技术可重用性的优点,可实现对已有驱动程序的兼容,但这些方法只是提供了一个替代整机承受系统崩溃的VM实例,并未解决VM内部操作系统的可靠性问题.如果VM内核的驱动出现错误,仍然会引起VM的崩溃,从而造成提供给用户的服务中断,甚至影响整机的可靠性.而且,为隔离一个驱动程序而运行一个单独的VM实例,也会带来不小的资源浪费.此外,还存在多种为了解决驱动程序所引起的操作系统可靠性问题的方法,但都存在某些局限性,不适合直接应用到虚拟化环境中.例如,微内核架构[9, 10, 11]和用户态驱动架构[12,13]与传统的操作系统架构和驱动架构不兼容,而且其性能损失较为严重.硬件架构的方法[14, 15, 16]往往较为复杂,开发难度较大,而且有些对底层硬件有特殊要求,有些需要修改驱动,也存在较大的性能损失.类型安全语言[17,18]一般都需要修改或者重写驱动程序,同样存在兼容性问题.

本文提出了一个通过在VM内隔离驱动程序,以提高VM内部操作系统可靠性的架构.该架构针对造成操作系统崩溃的最主要驱动故障(空指针和无效指针等非法写操作)[1, 2, 3],研究这类写操作故障的检测、隔离和恢复方法.通过监视VM中驱动程序的运行情况,建立驱动程序可写内存范围的授权表;在虚拟机监视器(VMM)中将VM的影子页表设置为只读,捕获驱动程序的写操作;结合授权表来判断驱动程序写操作的正确性,在发现驱动程序故障时,及时卸载驱动程序,防止驱动程序故障的扩散.目前,该架构已在KVM和Linux 2.6.28.10的环境中实现了对6种不同驱动程序的隔离.实验结果表明:本架构可以有效检查和隔离驱动程序错误,从而提高VM内部操作系统的可靠性.

本文第1节分析提高操作系统可靠性的研究现状.第2节介绍实现本架构的方法.第3节介绍架构的功能设计.第4节为本架构的实现.第5节是本架构的测试与效果分析.最后是结论和后续工作.

1 相关工作

利用虚拟化技术来隔离驱动程序的方法,如Xen[5,6],L4Ka[7]和iKernel[8]是将驱动隔离到独立的VM实例中,利用VM实例本身的隔离性来隔离驱动程序.然而,这种方法只是利用VM替代整机来承受可能出现的系统崩溃,从而换取整机可靠性的提高,对于VM内部操作系统的可靠性并未提高.为了避免因一个VM内部驱动程序故障引起的VM崩溃造成的服务中断,常常为每个驱动程序都建立一个VM实例来对外提供服务,这样也造成了较大的性能损失.VirtuOS[19]进一步划分单个VM内的操作系统,将不同功能隔离到不同的VM功能实例中,从而限制VM内核故障的影响范围,然而在每个VM功能实例内部驱动故障问题仍然存在.

硬件隔离方法,如Palladium[20]利用硬件的段保护机制实现对内核态或用户态扩展程序的隔离,但是该方法的编程模型较为复杂.FPD[21]采用硬件页保护机制实现对用户态扩展程序的隔离,提供判断策略来决定用户态的各种系统调用是否合法,但该方法未实现对内核态扩展程序的隔离.Nooks[15]通过复杂的同步和更新机制为驱动程序建立私有页表来限制其写权限,同时确保所有驱动和内核的交互都需要切换页表和堆栈,其开发难度大,不易于隔离新驱动程序,而且性能开销较大.Mondrix[14]混合软、硬件隔离技术,提供32位细粒度的权限控制以及保护域间切换的权限控制,该方法同样存在效率问题,而且需要特定硬件,存在兼容性问题.

软件隔离方法,如XFI[22]以低性能开销隔离简单的内核扩展程序,但是不能处理传统操作系统中的复杂扩展程序.BGI[23]通过手动注释各种可能内核和驱动间接口的方法扩展了XFI,从而可以处理更复杂的驱动接口,并利用授权表来限制驱动的运行,但它依赖于Windows驱动模型良好定义的API.LXFI[24]将BGI扩展到了复杂的Linux驱动接口,并可通过代理者来划分共享模块的特权级.FGFI[25]以单一入口粒度隔离驱动程序,并使用已有的电源管理代码来保存和恢复设备状态.但是这些方法都需要程序员清晰地注释内核和驱动接口,并修改驱动程序来添加运行时检查,使得对驱动程序的透明性较差.

SPIN[17],Sigularity[18]等以类型安全语言编写的操作系统和内核扩展程序可提供强大的内存隔离保证,但需要重写内核和扩展程序,并且不兼容已有的操作系统及其大量扩展程序,影响了这类方法的推广.SafeDrive[26]通过类型推断和程序员注释,由Deputy编译器自动生成运行时检查来保证驱动所操作的各种数据类型的安全,但它需要修改驱动程序的源代码,影响了对驱动程序的透明性,而且该方法的隔离性较差.Dingo[27]利用软件协议说明语言定义驱动的正确行为,并能有效检查驱动的同步故障和违反规范的行为失效,但同样也需要重写驱动程序.

有些系统将驱动程序隔离到独立的用户态进程地址空间,例如微内核[9, 10, 11]以及多种用户态驱动架构[12,13],这样,驱动程序的故障虽然只会造成对应的用户态进程的失效,不会造成系统崩溃,但微内核技术效率低,需要在用户态和内核态之间频繁地传递大量数据,对于高速硬件设备将造成严重的延时和性能损失;与传统宏内核操作系统不兼容,为了在传统操作系统中支持用户态驱动,需要修改内核并重写驱动.

综上分析可知:硬件隔离方法基本上都需要修改操作系统内核,其中有些方法还需要修改驱动程序,甚至要求特殊的硬件架构,开发难度较大,且大多数不能实现对驱动程序的透明性;软件隔离方法的安全隔离性能较差,且需要修改驱动程序,影响与原有驱动程序的兼容性;语言方法虽然性能较好,但需要修改驱动程序,同样对驱动程序不透明;微内核和用户态驱动存在与传统操作系统和驱动严重的兼容问题,且性能较差;当前,虚拟化技术虽然具有可重用性的优点,但是没有真正解决VM中驱动程序的可靠性问题.为此,本文设计了一种在VM内的隔离故障驱动程序的架构,该架构能够实现在VM内部对驱动程序的细粒度隔离,有效地捕捉驱动程序的异常,避免驱动程序故障造成VM崩溃以及VM所提供服务的中断.

2 原 理

在全虚拟化技术中,客户机(即VM实例)虚拟地址到宿主机物理地址的转换需要通过两级页表映射实现,如图 1所示.第1级页表映射位于VM内,为客户机虚拟地址到客户机物理地址的地址映射,如图 1中的VM页表g所示;第2级页表映射位于VMM中,为客户机物理地址到宿主机机器地址的地址映射,如图 1中的影子页表f所示.如果客户机要访问物理内存的内容,需复合两级页表映射f×g,并将其交给MMU来完成相应的操作.

Fig. 1 Two-Level page table mapping schematic in the full virtualization technology图 1 全虚拟化技术中两级页表映射示意图

由以上分析可知:VM内发生的任何写操作,都要经过VMM中第2级页表(也称影子页表)的地址映射f才能最终执行.即,真正记录写操作物理地址的页表位于VMM中.如果访问的地址在影子页表中不存在或为只读,则VM内的写操作将触发VMM的缺页异常.VMM的缺页异常将会根据引起缺页的具体原因进行相应的处理.因此,通过对影子页表的写权限进行适当的设置就可以捕获到写操作,以便进一步在缺页异常中验证写操作的正确性.

因此,本文驱动隔离架构的主要原理如下:

(1) 在驱动程序进行写操作前,将被隔离驱动所在VM的所有内核空间对应的影子页表f设置为只读(图 1中斜线所示,后面简称VM的影子页表),则可在VMM中捕捉到驱动的写操作;

(2) 在VMM中建立一个与被隔离驱动程序对应的记录VM内部可写内存范围的授权表P,如图 1阴影所示;

(3) 当VMM的缺页异常捕捉到驱动程序的写操作后,结合授权表P来判定驱动程序写操作的正确性;

(4) 如果正确,则允许写操作;否则,隔离驱动程序的写操作故障,防止驱动故障的扩散.

图 1所示,此时写操作目标地址的第2级页表地址映射由第2级页表本身的地址映射f和授权表P联合实现,即图中的f ¢.

3 架 构

本架构基于全虚拟化技术实现,其核心思想是:当驱动程序通过VMM中的影子页表实现写操作时,结合授权表来判断其写操作的正确性.它是通过驱动监视、隔离环境和错误处理三大功能模块来实现,如图 2所示:驱动监控功能负责将驱动的运行状态和使用的内存信息等实时报告给隔离环境功能;隔离环境功能根据驱动所使用内存信息建立驱动程序对应的授权表,并根据驱动的运行状态设置VM对应的影子页表,捕获驱动程序的写操作,建立起驱动隔离运行环境,在捕获到驱动写操作后,判断驱动写操作的正确性;当驱动出现写操作错误时,错误处理功能则负责停止故障驱动的工作,并释放驱动资源,以便移除故障驱动.本架构无需修改驱动程序,可确保对驱动程序的兼容性.

Fig. 2 Architecture of driver isolation inside VM图 2 VM内隔离驱动程序的功能架构
3.1 驱动监视

驱动监视功能负责监视驱动程序运行中的各种信息,主要包括:驱动运行所需的内存信息、运行状态信息以及用于区分写操作指令来源的可信内核范围信息等.

首先,为了构建图 1所示的授权表P,需要监视驱动程序正常运行所需的内存范围,这部分内存是驱动程序具有写权限才能正常运行的内核对象集合.具体内核对象包括:

(1) 堆内存:驱动通过内核的内存管理函数申请分配/释放的内存;

(2) I/O内存:驱动通过内核的端口映射函数映射/释放的内存;

(3) 栈内存:调用驱动函数的进程所在的栈,以及驱动程序本身所创建的内核线程所在的栈;

(4) 授予内存:内核传递给驱动函数使用的内核对象,或者驱动需要操作的全局内核变量.

其次,为了确保驱动程序写操作在执行前被捕获,以便进行正确性判断,需要及时地将图 1中的影子页表g设置为只读.这要求本架构能及时捕获驱动程序的各种运行状态消息,这些状态信息包括:

(1) 被隔离的驱动程序加载进入和卸载退出内核的消息,如图 3(a)、图 3(b)所示,前者用于通知VMM中的隔离环境功能进行授权表等隔离信息的创建和销毁工作;

Fig. 3 Schematic view of driver running states图 3 驱动程序的运行状态信息示意图

(2) 内核开始调用和结束调用驱动函数的消息,如图 3(c)、图 3(d)所示,后者用于通知隔离环境功能适时地进行影子页表的设置工作,以便捕获驱动程序的写操作.

最后,为了便于在VMM的缺页异常中判断捕获的VM写操作的正确性,还需要获取和记录可信内核范围等其他信息.相对于被隔离驱动程序,VM内核可信任的地址范围包括VM内核代码地址范围和未被隔离的其他驱动的地址范围.该信息用于辅助隔离环境功能进行写操作来源判断,以便进行适当的处理.

3.2 隔离环境

隔离环境为驱动程序提供一种限制权限的隔离运行环境,由被隔离驱动程序对应的授权表和设置了写保护的被隔离驱动所在VM的影子页表组成.它只提供驱动正常运行的最小内存资源.

授权表是被隔离驱动程序对VM内核地址空间具有写访问权限的地址集合.被隔离驱动程序只对属于授权表的VM内核空间具有写权限,对VM内核空间的其他部分只具有读权限.如图 3(a)~图 3(c)所示,授权表在驱动程序加载进内核时建立,在卸载出内核时销毁,并在运行过程中不断地被更新.通过接收驱动监视功能发出的被隔离驱动使用的内存信息,就可以实时地更新被隔离驱动程序可写内存范围的授权表.通过授权表,可以实现对VM内核任意粒度的内存保护.

为了捕获驱动程序的写操作,需要在驱动程序被调用前设置驱动程序所在VM对应的影子页表为只读.如图 3(c)、图 3(d)所示,通过接收驱动监视功能发出的驱动调用状态信息,隔离环境可及时设置VM对应的影子页表为只读,从而捕获VM的写操作.同样,在驱动程序被调用过程中,为了可持续捕获驱动程序的写操作,被允许的驱动程序写操作结束后,需将开放的影子页面的写权限重新设置为只读.为了避免将所有的影子页面设置为只读带来的性能损失,本文使用影子页面缓存的方法来优化影子页面设置的时机.其主要思想是:将最近访问到的影子页面先送入到缓存中,在延时一定时间后再将其设置为只读,以避免常用影子页面的写权限被反复设置(具体见第4.2节).

在驱动运行过程中,捕获到驱动程序的写操作后,结合授权表判断其写操作的正确性,具体流程如图 4所示.首先,根据驱动监视功能报告的可信内核范围,判断写操作来源.如果写操作来自被隔离驱动,则结合授权表继续判断驱动程序对于写操作地址是否具有写权限.如果驱动具有写权限,则将写操作地址对应的影子页面改为可写并执行写操作.在写操作结束后,将该页面送入影子页面缓存中,以便将来重新设置其写权限为只读.如果驱动不具有写权限,则跳过该指令,并报告被隔离驱动错误.如果写操作指令来自内核,则直接允许写操作,不需要结合授权表进行上述判断.

Fig. 4 Process of correctness judgement of driver write operation图 4 驱动程序写操作正确性判断流程
3.3 错误处理

错误处理功能主要用于在驱动程序出错后对驱动程序进行必要的处理,具体功能包括:跳过驱动程序的写操作、停止驱动程序进程、释放驱动程序所使用资源和卸载出错驱动程序等.

首先,在隔离环境检测到驱动故障后,向VM注入中断唤醒错误处理功能.在错误处理功能正式移除故障驱动之前,为了避免进一步执行驱动程序,VMM将跳过故障驱动的指令.同时,为了避免影子页面缓存泄漏对驱动写操作的捕获,在检测到驱动故障后,VMM设置整个VM对应的影子页面为只读,并停用影子页面缓存.

其次,故障驱动所在VM在接收到VMM发出的驱动故障信号后,需及时退出使用驱动程序的进程.为此,在内核中需要对驱动函数的调用进行适当的修改.主要包括以下步骤:

(1) 在调用驱动程序之前,将各寄存器的值以及驱动的出错返回地址记录到驱动程序栈中;

(2) 如果驱动程序正常运行,在驱动调用完成之后撤销上述记录信息;

(3) 如果驱动程序运行时出现错误,则恢复各寄存器值,并直接跳转到出错返回地址.

由于在检测到驱动错误时将直接跳转到出错返回地址,而不是按照正常的流程退出,此时进程可能持有部分锁资源.为了避免系统死锁,首先需要卸载驱动程序使用的锁资源,然后再卸载其他资源.各种内存资源是用于建立隔离环境中授权表的资源,这部分是驱动使用的主要资源;而驱动的各种注册信息是内核调用驱动的接口,通过移除这些信息就可避免内核进一步使用故障的驱动程序.

释放了故障驱动所使用的资源后,就可移除故障驱动模块.由于此时驱动程序已经出现错误,不能直接调用驱动程序自身的卸载函数来移除驱动模块,而要通过停止驱动程序,然后直接调用内核的模块卸载函数来释放驱动模块.如果需要,可以在卸载完故障驱动之后重新加载新的驱动程序,以便继续提供相应的服务.

4 实 现

目前,本架构已在以KVM作为底层VMM,以Linux 2.6.28.10作为VM内核的环境中实现了上述功能,并已实现对多种驱动程序的隔离.

4.1 驱动监视

驱动监视功能需要获取驱动所使用的各种资源信息、驱动运行状态以及可信内核范围.

4.1.1 内存资源

驱动所使用的内存信息包括堆内存、I/O内存、栈内存和授予内存的信息,下面通过实例来说明具体的内存信息获取过程.驱动涉及的堆内存是通过调用内存管理函数进行操作的内存,包括如下两个部分:

(1) 通过通用内存管理函数分配/释放的内存,这部分内存最为常见,如内存高速缓存的分配/释放函数kmallockfree;

(2) 通过某些特定数据结构的内存管理函数分配/释放的内存,如usb驱动中对urb结构体的分配/释放函数usb_alloc_urbusb_free_urb.

为了避免过多地修改VM内核,本框架选取这些内存管理函数都会调用到的底层内存管理函数作为驱动所使用内存信息的获取点,如在__cache_alloc函数中获取上述kmallocusb_alloc_urb分配的内存信息.如图 5中第9行所示,通过向__cache_alloc函数添加的注入内存信息语句来捕获驱动申请的slab内存信息.

Fig. 5 Obtain the heap memory information图 5 堆内存信息的获取

与堆内存类似,I/O内存是通过调用内核的I/O端口映射函数来申请,从而将硬件设备的资源映射到内存中.如,通过ioremap_nocache函数将硬件寄存器和内存等I/O空间资源映射到内核的内存中.同样,可在相应函数中添加注入语句实时地获得I/O内存的使用情况.

内核通过执行驱动接口中的函数指针字段实现对驱动的调用,如图 6中第11行所示.栈内存主要用于驱动函数内部变量的运算,其一般为一个或多个内存页面.通过内核的一些专用函数(如Linux系统中的current_ thread_info(×)函数),或者获取驱动函数的本地变量地址所在的页面,就可获取调用驱动函数的当前进程的栈资源.为保证驱动的正常运行,在执行接口函数前需要获取当前进程的内核栈,并将栈信息注入给隔离环境,如图 6中第5行所示.驱动程序可能被多个进程调用,这些不同的进程栈都需要被注入到授权表中.

Fig. 6 Obtain the stack and grant memory information图 6 栈和授权内存信息的获取

另外,内核还会通过这些接口函数的参数传递内核数据结构给驱动使用,这些授权内存信息也需要注入给隔离环境.这类内存常常以指针形式出现在驱动接口函数的参数中.如图 6中第6行所示,内核通过cmd指针参数传递一个struct scsi_cmnd类型的指令给底层驱动,并授权驱动程序操作该内存对象.除了指针参数指向的内存对象外,该内存对象的指针字段所指向的其他内存对象也可能被驱动使用,也需要一并注入.如图 6中第7行、第8行所示,struct scsi_cmnd结构体的sense_buffercmnd字段所指向的数据结构.由于驱动的栈内存和授权内存都涉及到驱动的接口函数,因此,同一接口函数可能同时涉及到这两类内存信息的注入.

usb-storage为例,表 1所示为监视各种内存资源需要修改的内核位置.可以看出:通过在底层函数监视堆内存,只需修改两个函数就可实现对U盘驱动程序所使用的堆内存进行监视.由于在Linux 2.6中驱动程序的功能较为强大,使得驱动程序的接口也较为复杂.相对于监视堆内存,监视栈内存需要修改的函数较多,但其数量仍然很有限.其中,部分函数还需同时添加对授予内存的监视代码.总体来说,利用本框架隔离一个驱动程序,需要修改的内核函数很少,可以很容易地实现对驱动程序的隔离.

Table 1 Modification places for monitoring memory usage of usb-storage 表 1 监视usb-storage内存资源需要修改的内核位置
4.1.2 资源跟踪

驱动程序在运行过程中所使用的内核资源,最主要的是第4.1.1节所介绍的内存资源.除此之外,还有许多其他内核资源,例如自旋锁和互斥锁等.为了便于驱动出现错误后移除故障驱动,同样需要实时记录这些内核资源.对这些资源的跟踪与第4.1.1节所述的内存资源的跟踪方法一致,都将被记录到一个驱动资源使用的哈希表中,以便错误处理时使用.所不同的是,内存资源需要被注入到VMM中,以便建立被隔离驱动程序的授权表,而其他内核资源则不需要注入.

4.1.3 驱动状态

为了获取被隔离驱动进入和退出内核的信息,需要修改内核的加载/卸载系统调用.如图 3所示,对于加载函数,在加载成功之后,需要为被隔离驱动程序创建相应的隔离域信息,并发出相应的建立授权表的指令;对于卸载函数,则做相反操作.

为了及时捕获驱动程序的写操作,需要在驱动程序被调用之前,通知VMM驱动程序被调用,并将VM的影子页表设置为只读;退出时,则需要做相反操作.内核对驱动程序的调用都是通过对标准接口函数调用来实现的,因此可以在接口函数调用语句前通知驱动即将被调用,在接口函数调用语句后通知驱动调用已经结束,如图 6中第9行和第13行所示.

4.1.4 可信内核范围

可信内核范围包括VM内核的代码段和未被隔离驱动程序的代码范围,用于区别写操作来源.VM内核代码范围可通过查询Linux的/boot目录下的System.map文件获得.该文件中_text和_etext符号记录着内核代码的起止位置.未隔离驱动程序的代码范围,可通过未隔离驱动程序对应的struct module结构体的module_corecore_size字段来获取.

4.1.5 消息注入

上述所有获取的驱动和内核信息,最终都需要注入到VMM中.本架构通过VMCALL陷入指令将这些信息主动注入到VMM中的隔离环境中.该指令通过寄存器EAX,EBX,ECX,EDX和ESI向VMM传递参数.因此,在调用VMCALL指令前,需将相关信息放置于这些寄存器中.

由于每个被隔离驱动在VMM中都有各自的隔离域信息以及授权表信息,为了区分不同的隔离驱动程序,在注入时需要指定是哪个驱动程序的注入信息.考虑到各种消息都是在修改过的相应内核函数中注入,而这些函数都和驱动接口函数直接或间接相关.因此,如果在进程调用驱动接口函数时就指定该进程是和某一隔离域相关,则后续进程在调用到这些函数时,也就知道应该注入到哪个隔离域中.为此,本架构需修改内核的进程结构体struct task_struct,为其添加一个隔离域字段isolation_domain.该字段进程在开始调用驱动接口函数时设置,步骤如下:

(1) 由于隔离域信息中记录了被隔离驱动的代码范围,通过查询驱动接口函数指针的地址(例如图 6中第11行的函数指针地址host®hostt®queuecommand)是否在其范围内,就可确定其属于哪个隔离域;

(2) 根据查询得到的隔离域信息,设置进程结构体task_structisolation_domain字段.这样,在后续注入信息时,就可直接根据当前进程的隔离域字段isolation_domain获得该注入信息属于哪个驱动程序.

4.2 隔离环境

实现隔离环境的关键是授权表的管理和影子页表的设置.为了确保本文的隔离架构切实可行,隔离环境需要在确保隔离效果的基础上,避免过多的性能开销.

4.2.1 授权表管理

VM内被隔离驱动程序对应的授权表是驱动程序对VM内核空间写访问权限的地址集合.由于驱动运行涉及的内存不断发生变化,本架构需要实时地对授权表进行建立、销毁、添加、删除、合并和查询等操作.如图 7所示,授权表中的所有表项以红黑树和升序链表的形式共同组织起来.红黑树主要用于在授权表中快速查询特定地址是否存在,而升序链表用于快速获得相邻地址范围的节点以便更新.由于红黑树中记录的是一段内存地址范围,对其节点保存的内存信息进行更新处理较为复杂.

Fig. 7 Structure of the authorization list图 7 授权表结构示意图
4.2.2 页面设置

通过将被隔离的驱动程序所在的VM整个内核空间对应的影子页表设置为只读,就可在缺页异常中捕获驱动写操作.理论上,本架构只在驱动运行期间将VM对应的影子页表设置为只读,其他情况下仍然保持可写权限.在驱动运行过程中,被允许的写操作所打开的影子页面权限,在写操作完成后,需重新被设置为只读.这样就可确保持续地捕获驱动程序的写操作.为实现影子页表的设置功能,本架构通过以下几个步骤来设置影子页表的写权限:

(1) 获取与VM虚拟地址对应的VM中各级页表及表项信息:若存在,继续下一步骤;否则,返回NULL;

(2) 逐级查询VM虚拟地址对应的影子页表:若存在,继续下一步;否则,返回NULL;

(3) 将查找到的影子页表的表项设置为只读.

然而,这种写操作捕获方法用在与内核频繁交互的驱动程序隔离,将带来严重的性能损失.部分经常访问的内存地址的写操作权限可能会被反复地打开和关闭.根据局部性原理,刚访问过的影子页面很可能在最近再次被访问到.为此,本架构利用一个影子页面缓存来延迟关闭最近访问到的影子页面的写权限,从而避免影子页面的写操作权限被反复地打开和关闭,如图 8所示.

Fig. 8 Schematic view of shadow page caching algorithm图 8 影子页面缓存算法原理示意图

首先,当被隔离驱动程序第1次被调用时,将设置被隔离驱动所在的VM对应的影子页表为只读,以便捕获驱动程序的写操作,如图 8(a)所示.在驱动运行过程中,如果开放了某个影子页面,则将其信息记录到开放影子页面缓存中.记录在缓存中的页面,在执行完写操作以后将暂时不被重新设置为只读.如果缓存满了,最久未被使用的缓存信息将被替换,并将被替换页面设置为只读,如图 8(b)左半部分所示.

其次,当被隔离驱动未调用时,由于之前设置所有影子页表为只读,此时仍有大量影子页面处于只读状态.考虑到遍历整个影子页表来重新打开写权限较为费时,仍然利用缺页异常来根据需要打开写权限.同时,考虑到内核在未调用驱动时访问的影子页面在调用驱动后也很可能被使用到,为了避免这些页面的写权限被反复设置,此时打开写权限的页面,仍然被送入开放影子页面缓存,而被替换出的影子页面则被送入开放影子页面池,如图 8(c)所示.这样,下次调用驱动时只需设置页面池中的影子页面即可,节省设置页面只读的时间,也避免将最近使用的页面设为只读.

最后,当驱动程序不是第1次被调用时,只需将开放影子页面池中的页面设为只读,即可保证驱动写操作的捕获,如图 8(b)右边部分所示.驱动运行期间影子页面的开放和设置,仍然如图 8(b)左半部分所示.

4.2.3 写操作判断

当VMM出现缺页异常时,需要先判断写操作来源再进行相应处理.为此,本架构通过修改KVM的缺页异常函数FNAME(page_fault)来添加相应的写操作判断功能.

当写操作指令来自可信任内核时,则具有写权限.KVM通过mmu_set_spte函数将只读页面设置成可写,并记录下开放写操作的影子页表,以便在经过一定的延时时间后由影子页面缓存操作重新将其设为只读.

当写操作指令来自被隔离驱动程序,且写操作地址位于该驱动的授权表范围内时,也进行上述操作;否则,跳过非法的写操作指令.跳过指令的操作步骤为:首先,读取当前指令和指令长度;然后,计算出下一指令的位置;最后,让KVM直接执行下一指令,避免执行驱动的非法指令.

4.3 错误处理

在驱动程序出错之后,为了及时退出驱动程序,本架构将强迫使用驱动程序的进程直接跳转到出错返回代码.因此,需要提前保存驱动的跳转地址以及出错前的寄存器状态.如图 6的第10行和第12行的宏所示,其展开的宏如图 9第1行~第22行所示.其中,图 6第10行的宏表示驱动程序被调用前的恢复准备工作,在调用驱动程序之前,将受影响的寄存器信息(图 9中第3行~第10行)以及出错返回地址信息会被保存在栈中(图 9中第4行、第5行).图 6第12行的宏表示驱动程序出错后的跳转位置(图 9中第18行)以及进一步的驱动故障恢复处理(图 9中第20行).驱动程序在运行过程中,可能出现驱动调用嵌套的情况.即:内核调用驱动函数之后,驱动函数又调用内核函数;接着,该内核函数又再次调用驱动函数,以此类推.对于出现驱动调用嵌套的情况,每一层对驱动的调用都需要保存寄存器和出错返回地址信息,并在出错时逐层跳转出驱动程序.

Fig. 9 Save and trigger the jump information of the driver图 9 驱动跳转信息的保存和触发

在VMM中的隔离环境功能检测到驱动出错之后,将调用kvmkvm_set_irq函数将中断注入到VM中,从而唤醒错误处理功能所注册过的驱动故障中断处理函数,该函数将启动正式驱动错误处理流程.如图 9中第23行~第35行所示,在驱动程序出错后,驱动故障中断处理函数被唤醒,恢复寄存器的值(图 9中第25行~第30行),并迫使使用驱动的进程直接跳转到出错返回地址(图 9中第31行).

在所有使用驱动程序的进程退出之后,驱动程序将根据驱动监视功能所跟踪的驱动资源使用情况来释放驱动资源.首先,为了避免死锁,先释放驱动使用的锁资源;然后根据后进先出的原则,依次释放其他资源.资源释放是通过调用各自的内核资源释放函数来完成的,例如,网卡中的skb资源通过kfree_skb释放,而I/O映射资源则调用iounmap来释放.

在释放完驱动的资源之后,错误处理功能最终调用内核通用模块卸载函数free_module来释放驱动模块,避免故障驱动被继续使用.这样就可以在不破坏内核的情况下,及时隔离驱动故障,并移除故障驱动.由于大多数驱动故障是瞬时故障,根据用户需要,可以重新加载驱动程序以继续提供硬件设备的服务功能.如果某个故障重复出现,很可能为确定性的故障,则不能继续重新加载驱动程序.同时,根据系统记录的故障日志,可以分析驱动故障的原因,以便修复驱动故障.

5 评 估

目前,本架构已经实现了6种常见驱动程序的隔离,见表 2.本节选用这些驱动程序对VM内部驱动隔离架构的特性进行评估,包括对VM内核可靠性的提高和对VM性能的影响.

Table 2 Drivers which are isolated by the driver isolation architecture inside VM 表 2 VM内驱动隔离架构所隔离的驱动程序
5.1 可靠性

本架构的重要目标是通过内存隔离来检测和限制驱动程序的写操作故障,防止驱动故障的扩散.为了检测架构对造成内存破坏的驱动故障的隔离效果,本文使用自动故障注入工具进行故障测试.

自动故障注入工具采用在Rio File Cache[28],Nooks[15]以及Mondrix[14]中使用的自动故障注入工具,我们将其移植到了Linux 2.6.28.10内核环境中.在加载了测试驱动模块后,通过指定注入的驱动名称、模拟的故障类型、注入故障个数以及随机数种子等,该工具通过随机改变内存中驱动程序的单一指令或多个指令,以模拟各种常见的编程错误.同时,在应用层运行使用到被测试驱动的应用程序,以触发注入的故障.

为了衡量对驱动故障的隔离效果,在测试中分别定义如下VM-Native和VM-Isolation两种测试环境.

(1) VM-Native:运行未修改的KVM和未修改的VM内核的测试环境;

(2) VM-Isolation:运行采用本文方法修改过的KVM和修改过的VM内核的测试环境.

每个注入故障都将分别在VM-Native和VM-Isolation两种环境下进行测试,以对比对驱动故障的隔离效果.为了充分体现本架构的隔离性能,本文对6个驱动分别进行了200次故障注入测试.

根据注入故障对VM-Native环境的破坏情况,本文将其分为3类:

(1) 崩溃失效:表明VM内核发生了致命性错误,出现无响应、宕机或自动重启等崩溃现象;

(2) 非致命性失效:表明VM未崩溃,但其中部分功能处于不正常状态;

(3) 静默失效:表明被破坏的数据暂时未被使用到,未表现出不正常.

根据VM-Isolation环境对造成VM-Native不同破坏情况的注入故障的隔离情况,本文将隔离效果分为隔离、捕获和丢失.

(1) 隔离:表示驱动故障被本架构成功地检查到,且故障驱动被顺利卸载;

(2) 捕获:表示驱动故障被本架构检测到,但是故障驱动未被成功卸载;

(3) 丢失:表示本架构未能检测到驱动故障.

图 10所示为VM-Isolation对造成VM-Native所在的VM各种失效的注入故障的隔离效果.如图 10(a)所示,在所有的故障注入测试中,有318次造成了系统崩溃,其中,266次崩溃被本架构成功地阻止并卸载了故障驱动,防止故障驱动继续破坏VM内核,隔离率为83.64%;还有51次也成功地捕获到了驱动故障,但未能卸载故障驱动,这种情况主要是因为没有及时结束正在使用故障驱动的进程,使得故障驱动无法卸载.

Fig. 10 Isolation effect of VM-Isolation to faults which cause crash,non-fatal and silent failures in VM-Native图 10 对于造成VM-Native环境系统各种失效的注入故障,VM-Isolation环境对这些故障的隔离效果

由于注入故障的位置是随机的,这些故障经过触发和传播后,破坏的VM内核位置也有所不同.有些异常行为可能不会造成VM内核的严重破坏,如网卡驱动可能出现路由不存在或者发送环满等非致命失效.考虑到注入的故障造成的失效很大部分属于此类失效,为此,本文也需要分析本架构对此类失效的隔离效果.

图 10(b)所示为VM-Isolation对造成VM-Native所在VM非致命性失效的注入故障的隔离效果.在所有6种驱动的故障注入测试中,有687次对VM-Native造成了非致命性失效,而VM-Isolation成功隔离了519次驱动故障,并捕获到了99次驱动故障,隔离率为75.54%.不过,仍然有69次失效没有被检测到.分析这些未被检测到的失效可知,其中很大一部分是由于注入故障使得驱动读取不存在的页面造成的,这种读操作失效并非本架构所能防止的驱动故障.例如在usb驱动未检测到的错误中,超过一半都属于这种类型,另外几种是由于输入输出错误造成的;网卡驱动中也有一大部分属于这种类型,其他则是由未能完成scp传递造成的.总体上,VM- Isolation减少了很多造成VM-Native非致命性失效的情况,特别是隔离了大多数驱动写操作引起的失效.

如果自动注入工具将故障注入到了不常执行的代码路径,这些故障就很可能不会被触发,也可能是在触发以后未造成明显的失效现象.不过,在这个过程中仍然可能存在写内存的操作,如果这些写操作位于驱动的授权表之外,虽然用户没有明显感觉到失效,但仍然可能被本架构所检测到.为此,本文同样分析VM内驱动隔离架构对这类失效的检查效果,图 10(c)所示为VM-Isolation对造成VM-Native所在静默失效的注入故障的隔离效果.总共有195次注入故障处于静默状态,本架构隔离到了151次故障,并检查到了8次故障,隔离率为77.43%,达到了很好的驱动隔离效果.

实验结果表明:本架构能够消除83.64%的系统崩溃,达到了架构的设计目标.同时,本架构对非致命性失效和静默失效也有很好的隔离效果,分别达到75.54%和77.43%,从而可以在驱动程序出现严重故障前,通知驱动程序进行提前恢复.在与本架构采用类似测试方法的硬件隔离架构Nooks[15]和Mondrix[14]中,Nooks针对致命性和非致命性故障的隔离率为99%和44.58%;Mondrix对致命性、非致命性和静默故障的隔离率为90%,39.1%和2.5%.相对来说,在致命性故障上,本架构在虚拟化环境中同样实现了较高隔离率.同时,在非致命性故障和静默故障上,本架构对这两类故障的隔离率则大为提高.因此,本架构成功地将硬件隔离方法扩展应用到了虚拟化环境中.综上所述,本架构可有效防止VM内部的驱动程序故障对VM内核的破坏,避免VM内核的崩溃,提高了VM内核的可靠性.

5.2 性 能

VM内驱动隔离架构的性能开销包括驱动内存使用的跟踪开销、影子页表缺页异常开销和写操作正确性检查开销等.本文通过一些基准测试程序来评估本架构对驱动正常运行造成的性能开销.由于本文研究的驱动隔离架构位于VM内,因此性能影响测试也在VM内完成.测试中所使用的计算机配置为Intel Core2 Duo CPU E8400、1.9G主频和4GB RAM,宿主机和客户机操作系统都为Centos 5.8,运行KVM的QEMU版本为qemu- kvm-1.2.0.网卡驱动测试利用两台相同的机器来完成.

网络驱动的性能开销使用netperf性能测试工具来测试TCP的发送和接收性能.在TCP测试中,发送缓存为16 384bytes,接收缓存为87 380bytes,发送的消息大小为16 384bytes.由表 3可知:e1000和rtl8139两种驱动,TCP的吞吐率下降1%~16%,CPU使用率增加大约2%~25%.由于网卡驱动会频繁地调用中断处理程序,其数据发送、接收以及状态查询也都通过中断来完成,这使得其驱动调用次数也较多,影子页表被设置的次数和写操作引起的缺页次数增多,最终导致网卡驱动的性能损失相对较大.但是总体来说,本架构对于网卡驱动的性能损失都在可接受的范围内.

Table 3 Performance of driver isolation architecture inside VM 表 3 VM内驱动架构的性能开销

为了衡量本架构对硬盘驱动的影响,分别在scsi硬盘和U盘中解压缩文件进行基准测试.由表 3(声卡驱动的性能为运行时间,其余驱动为吞吐率)可知:usb_storage的吞吐率下降5.4%,CPU使用率增加大约23.43%;而sd_mod的解压缩时间增加2.3%,CPU使用率增加大约5%.这种性能损失的不同,与驱动的数据处理方式有关. usb_storage驱动会创建自己的进程来处理块设备请求,该进程在没有请求时会处于睡眠状态.当需要处理新数据时,内核需要调度该进程,带来一些时间开销.而且在VM-Isolation中,由于影子页表被设置为只读,内核调度过程的写操作也会产生缺页异常处理,因此其开销会相对较大.而sd_mod由内核进程直接调用其接口函数来处理块设备请求,无需进程调度,开销相对较小.

声音基准通过mplayer以128kbit每秒播放一个MP3文件来测试.由表 3可知,两种声卡驱动的时间增加都小于0.1%,CPU使用率增加小于0.11%.可见,本架构对声卡程序的性能基本无影响.虽然声卡驱动和网卡驱动都存在中断,但声卡驱动并不使用中断处理数据请求,使其驱动被调用次数明显小于网卡驱动,故性能损失较小.

综上所述,VM内驱动隔离架构虽然对驱动的性能造成了一定的影响,但是都在可接受的范围内,小于16%.其中,除了网卡驱动的性能损失相对较大外,对其他驱动程序的性能影响很小.在当前利用VM实例进行隔离的Xen[6]和L4Ka[7]中,Xen隔离的网卡驱动和硬盘驱动的性能损失分别为3%~18%和1%,L4Ka隔离的网卡驱动和硬盘驱动的性能损失分别为8%~25%和2.4%.相对来说,本架构对于隔离这两类驱动带来的性能损失也在类似范围内(网卡驱动为1%~16%,硬盘驱动为2.3%~5.4%).另外,由于本架构为了充分验证其隔离的有效性,在实验评估中所测试的驱动程序也比这两种方法要多(甚至包括它们所未测试的声卡驱动),因此可以充分说明,本架构不会对被隔离驱动带来严重的性能损失.

6 结束语

本文介绍了一种通过隔离驱动程序提高VM可靠性的架构,本架构能兼容已有的驱动程序,在VM内部实现对驱动程序的有效隔离,从而提高VM的可靠性.本架构通过监控驱动程序使用的内存资源来及时更新驱动授权表,基于监控驱动运行状态设置VM对应的影子页表写保护,从而构建驱动的隔离运行环境,保证驱动程序写操作的正确性,避免驱动错误扩散到VM内核.

目前,本架构的实现仍然依赖于对VM内核代码的少量修改,从而限制了架构的移植性.下一步,我们将研究在不修改VM内核的情况下实现本架构,并完善驱动程序的错误检查和恢复功能.

致谢 在此,我们向浪潮公司对本文的工作所给予的支持和建议表示由衷的感谢.

参考文献
[1] Andy C, Junfeng Y, Benjamin C, Seth H, Dawson E. An empirical study of operating systems errors. In: Proc. of the 18th ACM Symp. on Operating Systems Principles (SOSP). New York, 2001. 73-88 .
[2] Ganapathi A, Ganapathi V, Patterson D. Windows XP kernel crash analysis. In: Proc. of the 20th Conf. on Large Installation System Administration (LISA). Berkeley: USENIX Association, 2006. 101-112. http://dl.acm.org/citation.cfm?id=1267805
[3] Nicolas P, Gaël T, Suman S, Christophe C, Julia L, Gilles M. Faults in Linux: Ten years later. In: Proc. of the 16th Int’l Conf. on Architectural Support for Programming Languages and Operating Systems (ASPLOS). New York, 2011.305-318 .
[4] Jim G. Why do computers stop and what can be done about it. In: Proc. of the 5th Symp. on Reliability in Distributed Software and Database Systems (SRDS). Los Angeles: IEEE Computer Society Press, 1986. 3-12. http://dl.acm.org/citation.cfm?id=21794
[5] Peter C, Brian N. When virtual is better than real. In: Proc. of the 8th USENIX Workshop on Hot Topics in Operating Systems (HOTOS). Washington: IEEE Computer Society, 2001. 133-138.http://dl.acm.org/citation.cfm?id=876409
[6] Keir F, Steven H, Rolf N, Ian P, Andrew W, Mark W. Safe hardware access with the Xen virtual machine monitor. In: Proc. of the 1st Workshop on Operating System and Architectural Support for the on demand IT InfraStructure (OASIS). New York: ACM, 2004. 1-10. http://www.sigops.org/announce/Aug04Sigops.htm
[7] Joshua L, Volkmar U, Jan S, Stefan G. Unmodified device driver reuse and improved system dependability via virtual machines. In: Proc. of the 6th USENIX Symp. on Operating Systems Design & Implementation (OSDI). Berkeley: USENIX Association, 2004. 1-14. http://dl.acm.org/citation.cfm?id=1251256
[8] Lin T, Ellick C, Reza F, Nevedita M, Jeffrey C, Francis D, Roy C. iKernel: Isolating buggy and malicious device drivers using hardware virtualization support. In: Proc. of the 3rd IEEE Int’l Symp. on Dependable, Autonomic and Secure Computing (DASC). Washington, 2007.134-144 .
[9] Jorrit H, Herbert B, Ben G, Philip H, Andrew T. MINIX 3: A highly reliable, self-repairing operating system. SIGOPS Operating Systems Review, 2006,40(3):80-89 .
[10] Dan W, Patrick R, Kevin W, Emin S, Fred S. Device driver safety through a reference validation mechanism. In: Proc. of the 8th USENIX Symp. on Operating Systems Design & Implementation (OSDI). Berkeley: USENIX Association, 2008. 241-254. http://dl.acm.org/citation.cfm?id=1855758
[11] Peter C. Get more device drivers out of the kernel. In: Proc. of the Linux Symp. 2004. Ottawa, 2004. 149-161.http://www.linuxsymposium.org/2004/
[12] Vinod G, Arini B, Michael SW, Somesh J. Microdrivers: A new architecture for device drivers. In: Proc. of the 11th USENIX Workshop on Hot Topics in Operating Systems. Berkeley: USENIX Association, 2007. 151-156. http://dl.acm.org/citation.cfm?id=1361412
[13] Ben L, Peter C, Nicholas F, Stefan G, Charles G, Luke M, Daniel P, Yueting S, Kevin E, Gernot H. User-Level device drivers: Achieved performance. Journal of Computer Science and Technology, 2005,20(5):654-664 .
[14] Emmett W, Junghwan R, Krste A. Mondrix: Memory isolation for Linux using mondriaan memory protection. In: Proc. of the 20th ACM Symp. on Operating Systems Principles (SOSP). New York, 2005.31-44 .
[15] Michael S, Henry L, Brian B. Improving the reliability of commodity operating systems. In: Proc. of the 19th ACM Symp. on Operating Systems Principles (SOSP). New York, 2003.207-222 .
[16] Zheng H, Zhang XJ, Wang ED, Wu N, Dong XS. Achieving high reliability on Linux for k2 system. In: Proc. of the 2012 IEEE/ ACIS 11th Int’l Conf. on Computer and Information Science (ICIS). Washington, 2012.107-112 .
[17] Brian B, Stefan S, Przemysław P, Emin S, Marc F, David B, Craig C, Susan E. Extensibility safety and performance in the spin operating system. ACM SIGOPS Operating Systems Review, 1995,29(5):267-283 .
[18] Galen H, James L. Singularity: Rethinking the software stack. ACM SIGOPS Operating Systems Review, 2007,41(2):37-49 .
[19] Ruslan N, Godmar B. VirtuOS: An operating system with kernel virtualization. In: Proc. of the 24th ACM Symp. on Operating Systems Principles (SOSP). New York, 2013.116-132 .
[20] Tzi-cker C, Ganesh V, Prashant P. Integrating segmentation and paging protection for safe, efficient and transparent software extensions. In: Proc. of the 17th ACM Symp. on Operating Systems Principles (SOSP). New York, 1999. 140-153 .
[21] Takahiro S, Kenji K, Takashi M. A hierarchical protection model for protecting against executable content. Technical Report, 2003.
[22] Úlfar E, Martín A, Michael V, Mihai B, George CN. XFI: Software guards for system address spaces. In: Proc. of the 7th USENIX Symp. on Operating Systems Design & Implementation (OSDI). Berkeley: USENIX Association, 2006. 75-88. http://dl.acm.org/citation.cfm?id=1298455.1298463&coll=DL&dl=ACM&CFID=551835625&CFTOKEN=44516859
[23] Miguel C, Manuel C, Jean-Philippe M, Marcus P, Periklis A, Austin D, Paul B, Richard B. Fast byte-granularity software fault isolation. In: Proc. of the 22nd ACM Symp. on Operating Systems Principles (SOSP). New York, 2009.45-58 .
[24] Mao YD, Chen HG, Zhou D, Wang X, Zeldovich N, Kaashock MF. Software fault isolation with API integrity and multi-principal modules. In: Proc. of the 23rd ACM Symp. on Operating Systems Principles (SOSP). New York, 2011.115-128 .
[25] Asim K, Matthew R, Michael S. Fine-Grained fault tolerance using device checkpoints. In: Proc. of the 18th Int’l Conf. on Architectural Support for Programming Languages and Operating Systems (ASPLOS). New York, 2013. 473-484 .
[26] Feng Z, Jeremy C, Zachary A, Ilya B, Rob E, Matthew H, George N, Eric B. SafeDrive: Safe and recoverable extensions using language-based techniques. In: Proc. of the 7th USENIX Symp. on Operating Systems Design & Implementation (OSDI). Berkeley: USENIX Association, 2006. 45-60. http://dl.acm.org/citation.cfm?id=1298455.1298461&coll=DL&dl=ACM&CFID=551835625&CFTOKEN=44516859
[27] Leonid R, Peter C, Ihor K, Etienne S, Gernot H. Automatic device driver synthesis with termite. In: Proc. of the 22nd ACM Symp. on Operating Systems Principles (SOSP). New York, 2009.73-86 .
[28] Peter C, Wee N, Subhachandra C, Christopher A, Gurushankar R, David L. The Rio file cache: Surviving operating system crashes. ACM SIGOPS Operating Systems Review, 1996,30(5):74-83 .