KylinX:A Dynamic Library Operating System for Simplified and Efficient Cloud ~

1,691 阅读43分钟

正文之前

仿佛好久没写过东西了。。刚才一翻,最新文章在1-19,三个月了。。。果然我已经快放弃简书了,不过这儿好歹承载了那么多的回忆,还是别丢了吧。以后把我翻译的一些论文丢上来算了。。

正文

~原文我都用CAJviewer识别出来,并且整理过了,有需要的请私信我~ 或者发我邮箱:1184827350@qq.com询问好了。下面我只放中文的内容了,(全篇大部分google翻译,然后人读一遍粗略修改过。有些地方可能还是不太通顺,不过那就基本代表我也不大懂了。。。)里面还有一些【】里面的内容是我自己做的标注,可以忽略


Unikernel专门简化LibOS和目标应用到一个独立的单一用途的虚拟机(VM)上运行在Hypervisor上,这被称为(虚拟)设备。 与传统VM相比,Unikernel设备具有更小的内存占用和更低的开销,同时保证了相同的隔离级别。 在缺点方面,Unikernel剥离了其整体设备的流程抽象,从而牺牲了灵活性,效率和适用性。

本文探讨了Unikernel设备(强隔离)和流程(高灵活性/高效率)的最佳平衡。 我们提供KylinX,一个动态库操作系统,通过提供pVM(类似进程的VM)抽象,实现简化和高效的云虚拟化。 pVM将虚拟机Hypervisor作为操作系统,将Unikernel设备作为允许页面级和库级动态映射的进程。

  • 在页面级别,KylinX支持pVM fork以及一组用于pVM间通信(IpC)的API。
  • 在库级别,KylinX支持在运行时链接到Unikernel设备的共享库。

KylinX对潜在威胁实施映射限制。 KylinX可以在大约1.3毫秒内分叉pVM,并在几毫秒内将库链接到正在运行的pVM,两者都与Linux上的进程分支相当(大约1毫秒)。 KylinX IpC的延迟也与UNIX IPC的延迟相当。

1 介绍

商品云(如EC2 [5])提供了一个公共平台,租户租用虚拟机(VM)来运行他们的应用程序。 这些基于云的VM通常专用于特定的在线应用程序,如大数据分析[24]和游戏服务器[20],并被称为(虚拟)设备[56,64]。 高度专业化的单一用途设备只需要传统操作系统支持的一小部分来运行其容纳的应用程序,而当前的通用操作系统包含广泛的库和功能,形成最终多用户,多应用程序场景。设备的单一用途的使用和传统操作系统的通用设计之间的失配引起的性能和安全性惩罚,使基于设备的服务的部署和安排变得繁琐[62,52],运行效率低[56],并容易受到不必要的库的影响[27]。

这个问题最近推动了Unikernel [56]的设计,这是一个库操作系统(LibOS)架构,旨在实现云中高效安全的设备。 Unikernel将传统操作系统重构为库,并将应用程序二进制和必需库封装成专用的应用镜像,该映像可直接在 Xen [ 30]和KVM [22] 等虚拟机Hypervisor上运行。与传统VM相比,Unikernel设备去掉了未使用的代码:

  • 实现了更小的内存占用
  • 更短的启动时间
  • 更低的开销
  • 同时保证了相同的隔离级别。

虚拟机Hypervisor的稳定接口避免了早期LibOS遇到的硬件兼容性问题[39]。 【Mark: 早期LibOS可以一看】

在缺点方面,Unikernel剥离了其静态密封的单片设备的过程提取,因此牺牲了灵活性,效率和适用性。 例如,Unikernel不能支持动态fork,这是传统UNIX应用程序常用的多进程抽象的基础; 并且编译时导致的不可变性使得运行时无法管理,例如在线库更新和地址空间随机化。 这种缺陷在很大程度上降低了Unikernel的适用性和性能。

在多任务操作系统中,进程(运行的程序)需要一种方法来创建新进程,例如运行其他程序。Fork及其变种在类Unix系统中通常是这样做的唯一方式。如果进程需要启动另一个程序的可执行文件,它需要先Fork来创建一个自身的副本。然后由该副本即“子进程*”*调用exec系统调用,用其他程序覆盖自身:停止执行自己之前的程序并执行其他程序。

Fork**操作会为子进程创建一个单独的地址空间。子进程拥有父进程所有内存段的精确副本。在现代的UNIX变种中,这遵循出自SunOS-4.0的虚拟内存模型,根据写入时复制语义,物理内存不需要被实际复制。取而代之的是,两个进程的虚拟内存页面可能指向物理内存中的同一个页,直到它们写入该页时,写入才会发生。在用fork配合exec来执行新程序的情况下,此优化很重要。通常来说,子进程在停止程序运行前会执行一小组有利于其他程序的操作,它可能用到少量的其父进程的数据结构

当一个进程调用fork时,它被认为是父进程,新创建的进程是它的孩子(子进程)。在fork之后,两个进程还运行着相同的程序,都像是调用了该系统调用一般恢复执行。然后它们可以检查调用的返回值确定其状态:是父进程还是子进程,以及据此行事。

fork**系统调用在第一个版本的Unix就已存在[1],它借用于更早的GENIE分时系统[2]Fork**是标准化的POSIX的一部分

在本文中,我们将研究是否存在平衡,以获得Unikernel设备(强隔离)和进程(高灵活性/高效率)的最佳性能。 在虚拟机Hypervisor(Hypervisor)上的应用程序和传统操作系统上的进程之间进行类比,从静态Unikernel向前迈出一步,就有了KylinX,这是一个动态库操作系统,通过提供pVM(process-like VM)抽象来实现简化和高效的云虚拟化。 我们将虚拟机Hypervisor作为操作系统和允许pVM的页级和库级动态映射的进程一样的应用程序。

【Hypervisor,又称虚拟机器监视器(英语:virtual machine monitor,缩写为 VMM),是用来建立与执行虚拟机器的软件、固件或硬件。 被Hypervisor用来执行一个或多个虚拟机器的电脑称为主体机器(host machine),这些虚拟机器则称为客体机器(guest machine)。hypervisor提供虚拟的作业平台来执行客体操作系统(guest operating systems),负责管理其他客体操作系统的执行阶段;这些客体操作系统,共同分享虚拟化后的硬件资源。】

  • 在页面级别,KylinX支持pVM fork和一组用于inter-pVM communication(IpC)的API,它与传统的UNIX进程间通信(IPC)兼容。 IpC的安全性通过仅允许从同一个根pVM分叉的相互受信任的pVM之间的IpC得到保证。
  • 在库级别,KylinX支持共享库,动态链接到Unikernel设备,使pVM能够执行(i)在线库更新,在运行时将旧库替换为新库,以及(ii)重用内存域以进行快速启动。 我们分析动态映射引发的潜在威胁并实施相应的限制。

我们通过修改MiniOS [14](用C编写的Unikernel LibOS)和Xen'stoolstack实现了基于Xen [30](1型Hypervisor)的KylinX原型。 KylinX可以在大约1.3毫秒内分配pVM,并在几毫秒内将库链接到正在运行的pVM,这两者都与Linux上的进程分支相当(大约1毫秒)。 KylinX IpC的延迟也与UNIX IPC相当。对实际应用程序(包括Redisserver [13]和Web服务器[11])的评估表明,Kylin在保留隔离保证的同时,比静态Unikernel具有更高的适用性和性能。

本文的其余部分安排如下。 第2节介绍了背景和设计选项。第 3 节介绍了具有安全限制的动态定制的KylinX LibOS的设计 。 第4节报告了KylinX原型实现的评估结果。 第5节介绍相关工作。 第6节总结了论文并讨论了未来的工作。

2 背景

2.1 VM ,容器和Picoprocesses

虚拟化和隔离的文献中有几种传统模型:进程,Jails和VM。

  1. OS进程。 进程模型是针对传统的(部分信任)操作系统环境,并提供丰富的ABI(应用程序二进制接口)和交互性,使得它不适合真正的交付给租户。
  2. FreeBSD Jails [47]。 jail模型提供了一种轻量级机制来分离应用程序及其相关策略。它在传统操作系统上运行一个进程,但限制了几个系统调用接口以减少漏洞。
  3. VMs。 VM模型构建隔离边界匹配硬件。 它为guest虚拟机提供了运行完整操作系统的传统兼容性,但对于重复和残留的操作系统组件而言,这是非常昂贵的。

虚拟机(图1(左))已被广泛用于多租户云, 因为它保证了强大的(类型-监督)隔离[55]。 但是,VM的当前虚拟化体系结构非常繁重,包括高级Hypervisor,VM,OS内核,进程,语言运行时( 如glibc [16]和JVM [21]),库和应用程序,它们很复杂,无法再满足商业云的效率要求。

容器(如LXC [9]和Docker [15])利用内核功能来打包和隔离进程。他们最近需求量很大[25,7,6],因为与VM相比它们很轻。但是,容器比在隔离性上比VM更弱,因此它们经常在VM中运行以实现适当的安全保障[58]。

【 Docker容器实现原理及容器隔离性踩坑介绍: http://dockone.io/article/8148

Picoprocesses [38](图1(中))可以被视为具有更强隔离性但更轻量级的容器。他们使用主机操作系统和客户机之间的小型接口来实现LibOS,实现主机ABI并将高级客户机API映射到小接口。 Picoprocesses特别适合客户端软件交付,因为客户端软件需要在各种主机硬件和操作系统组合上运行[38]。它们也可以在hvpervisors上运行【62,32】。

最近对picoprocesses的研究[67,32,54] 通过允许dynamics来重新启动原始静态隔离模型。 例如,Graphene [67]支持picoprocess fork和multi-picoprocess API,而Bascule [32]允许OS-independent扩展附加到运行时的picoprocess。 虽然这些松弛会稀释严格的隔离模型,但它们有效地将picoprocesses的适用范围扩展到更广泛的应用范围。

2.2 Unikernel Appliances

基于进程的虚拟化和隔离技术面临来自用于与主机操作系统交互的广泛内核系统调用API的挑战。例如,进程/线程管理,IPC,网络等.Linux系统调用已达到近400 [3]并且是不断增加,并且系统调用API比VM的ABI( 可以利用硬件内存隔离和CPU环) 更难以保护 [58]。

最近,研究人员提出减少VM,而不是增加进程,以实现安全和高效的云虚拟化。Unikernel [56]专注于单应用程序VM设备[26],并将Exokernel [39]样式的LibOS应用于VM guest虚拟机,以提高性能优势,同时保留1类虚拟机Hypervisor的强隔离保证。它打破了传统的通用虚拟化架构(图1(左)),并将OS功能(例如,设备驱动程序和网络)实现为库。与其他基于Hypervisor的简化虚拟机(如Tiny CoreLinux [19]和OS 0 [ 49])相比,Unikernel仅将应用程序及其必需的库封装到镜像中。

【Mark:Exokernel is an operating system kernel developed by the MIT Parallel and Distributed Operating Systems group,[1] and also a class of similar operating systems.

Operating systems generally present hardware resources to applications through high-level abstractions such as (virtual) file systems. The idea behind exokernels is to force as few abstractions as possible on application developers, enabling them to make as many decisions as possible about hardware abstractions.[2] Exokernels are tiny, since functionality is limited to ensuring protection and multiplexing of resources, which is considerably simpler than conventional microkernels' implementation of message passing and monolithic kernels' implementation of high-level abstractions.

Implemented applications are called library operating systems; they may request specific memory addresses, disk blocks, etc. The kernel only ensures that the requested resource is free, and the application is allowed to access it. This low-level hardware access allows the programmer to implement custom abstractions, and omit unnecessary ones, most commonly to improve a program's performance. It also allows programmers to choose what level of abstraction they want, high, or low.

Exokernels can be seen as an application of the end-to-end principle to operating systems, in that they do not force an application program to layer its abstractions on top of other abstractions that were designed with different requirements in mind. For example, in the MIT Exokernel project, the Cheetah web server stores preformatted Internet Protocol packets on the disk, the kernel provides safe access to the disk by preventing unauthorized reading and writing, but how the disk is abstracted is up to the application or the libraries the application uses. https://en.wikipedia.org/wiki/Exokernel*】*

l 【类型I:本地或裸机Hypervisor

l 类型II:Hosted Hypervisor】

由于Hypervisor已经提供了传统操作系统的许多管理功能(例如隔离和调度) ,因此Unikernel采用了(minimalism philosophy)极简主义哲学[36],它不仅通过删除不必要的库而且还从其LibOS中剥离了重复的管理功能来最小化VM。 例如,Mirage[57]遵循多核模型[31]并利用虚拟机Hypervisor进行多核调度,使单线程运行时可以具有快速的顺序性能; MiniOS [14]依赖于Hypervisor( 而不是in-LibOS链接器)来加载/链接设备启动时间; 而LightVM [58]通过重新设计Xen的控制平面实现了快速VM启动。

2.3 动机和设计选择

Unikernel设备和传统的UNIX进程可以抽象出隔离,特权和执行状态的单元,并提供内存映射,执行协作和调度等管理功能。为了实现低内存占用和小型计算基础(TCB),Unikernel剥离了其单片设备的进程抽象,并将简约LibOS与其目标应用程序相链接,展示了依靠虚拟机Hypervisor消除重复功能的好处。但在缺点方面,进程和编译时确定的整体性大大降低了Unikernel的灵活性,效率和适用性。

【TCB是Trusted Computing Base的简称,指的是计算机内保护装置的总体,包括硬件、固件、软件和负责执行安全策略的组合体。它建立了一个基本的保护环境并提供一个可信计算机系统所要求的附加用户服务。】

如图1(右)所示,KylinX通过将虚拟机Hypervisor显式为一个OS,而将Unikernel设备作为进程显式提供pVM抽象。 KylinX轻松放松了Unikernel的编译时单片性要求,允许页面级和库级动态映射,这样pVM就可以拥有Unikernel设备和UNIX进程的最佳性能。如表1所示,KylinX可以被视为对Unikernel的扩展(提供pVM抽象),类似于Graphene [67](提供传统的多工艺兼容性)和 Bascule [ 32](提供运行时可扩展性)的扩展到picoorocess。

出于以下原因,我们在Hypervisor而不是guestLibOS中实现KylinX的动态映射扩展。

  1. 首先,guestLibOS外部的扩展允许Hypervisor强制执行映射限制(第 3.2.3节和第3.3.3节),从而提高安全性。

  2. 其次,Hypervisor更灵活地实现动态管理,例如,在pVM的在线库更新期间恢复实时状态(第3.3.2节)。

  3. 第三,KylinX很自然地遵循Unikernel的极简主义哲学(第2.2章),利用虚拟机Hypervisor来消除重复的客户LibOS功能。

向后兼容性是另一种权衡。 最初的Mirage Unikernel [56]占据了一个极端的位置,现有的应用程序和库必须在OCaml [10]中完全重写,以确保类型安全,这需要大量的工程工作,并可能引入新漏洞。 相比之下,KylinX旨在支持源代码(主要是C)兼容性,因此可以在KylinX上运行各种各样的遗留应用程序,只需最少的调整工作。

威胁模型。 KylinX采用传统的威胁模型[56,49],与Unikernel相同的上下文[ 56],其中 VM/pVM 在虚拟机Hypervisor上运行,并且有望在公共多租户云中提供面向网络的服务。 我们假设攻击者可以在VM/pVM中运行不受信任的代码,并且在VM/pVM中运行的应用程序受到来自同一云中的其他人和来自通过Internet连接的恶意主机的潜在威胁。KylinX将虚拟机Hypervisor(使用其工具堆栈)和控制域(dom0)视为TCB的一部分,并利用虚拟机Hypervisor隔离其他租户的攻击。使用SSL和SSH等安全协议有助于KylinX pVM对外部实体进行信任。

www.ibm.com/developerwo…

------------------------------------------------------------------------------

Dom0 is the initial domain started by the Xen hypervisor on boot. Dom0 is an abbrevation of "Domain 0" (sometimes written as "domain zero" or the "host domain"). Dom0 is a privileged domain that starts first and manages the DomU unprivileged domains. The Xen hypervisor is not usable without Dom0

A DomU is the counterpart to Dom0; it is an unprivileged domain with (by default) no access to the hardware. It must run a FrontendDriver for multiplexed hardware it wishes to share with other domains. A DomU is started by running

英特尔软件Guard eXtensions(SGX)[12]等硬件的最新进展证明了屏蔽执行的可行性,并以保护VM/pVM免受特权虚拟机Hypervisor和dom0 [33,28,45]破坏的可行性,这将在我们未来的工作中进行研究。 我们还假设硬件设备没有受到损害,尽管已经确定了硬件威胁[34]。

3 KylinX 设计

3.1概述

KylinX扩展了Unikernel,以实现以前仅适用于进程的理想功能。我们不是从零开始设计一个新的LibOS,而是基于MiniOS构建KylinX [27],这是一个在Xen虚拟机Hypervisor上运行的用户VM域(domU)的C风格Unikernel LibOS. MiniOS 使用其前端驱动程序访问硬件,连接到相应的硬件特权dom0或专用驱动程序域中的后端驱动程序.MiniOS具有单个地址空间,没有内核和用户空间分隔,也没有抢占的简单调度程序。 MiniOS很小巧但适合在Xen上采用整洁高效的LibOS设计。 例如,Erlang on Xen [1],LuaJIT [2],C1ickOS [59]和LightVM [58]分别利用MiniOS提供 Erlang,Lua ,Click和快速启动环境。 【Marked:Xen虚拟化基本原理详解 blog.51cto.com/wzlinux/172… Mini-OS: wiki.xenproject.org/wiki/Mini-O…

如图2所示,基于MiniOS的KylinX设计包括(i)DomO中Xen工具堆栈的(受限制的)动态页面/库映射扩展,以及(ii)进程抽象支持(包括动态pVMfork/IpC和运行时pVM)库链接)在DomU。

3.2 动态页面映射

KylinX通过利用Xen的共享内存和授权表来执行跨域页面映射,从而支持进程式设备分支和通信。

3.2.1 pVM Fork

fork API是实现pVM传统多进程抽象的基础。 KylinX将每个用户域(pVM)视为一个进程,当应用程序调用fork()时,将生成一个新的pVM。

我们利用Xen的内存共享机制实现fork操作,它通过 (i)复制xc_dom_image结构 (ii)调用Xen的unpause()API来分叉调用父pVM并将其域ID返回给父级来创建child pVM。

如图3所示,当在父pVM中调用fork() 时,我们使用内联汇编来获取CPU寄存器的当前状态并将它们传递给子寄存器。控制域(dom0)负责分支和启动子pVM。 我们修改libxc以在创建父pVM时将xc_dom_images结构保留在内存中,这样当调用fork()时,结构可以直接映射到子pVM的虚拟地址空间,然后父进程可以使用授权表与子进程进行共享。以可写数据以写时复制(CoW)方式共享。 【Copy-on-write (CoW or COW), sometimes referred to as implicit sharing[1] or shadowing,[2] is a resource-management technique used in computer programming to efficiently implement a "duplicate" or "copy" operation on modifiable resources.[3] If a resource is duplicated but not modified, it is not necessary to create a new resource; the resource can be shared between the copy and the original. Modifications must still create a copy, hence the technique: the copy operation is deferred to the first write. By sharing resources in this way, it is possible to significantly reduce the resource consumption of unmodified copies, while adding a small overhead to resource-modifying operations. 如果资源重复但未修改,则无需创建新资源; 资源可以在副本和原始文件之间共享。 修改必须仍然创建一个副本,因此技术:复制操作被推迟到第一次写入。 通过以这种方式共享资源,可以显着减少未修改副本的资源消耗,同时为资源修改操作增加一小部分开销 en.wikipedia.org/wiki/Copy-o…

通过unpause()启动子pVM之后,它(i)接受来自其父级的共享页面,(ii)恢复CPU寄存器并跳转到fork之后的下一条指令,以及(iii)开始作为子级运行。在完成fork()之后 ,KylinX异步初始化一个事件通道并在父子pVM之间共享专用页面以启用它们的IpC,如下一小节中所介绍的。

3.2.2 inter-pVM通信(IpC)

KylinX提供了一个多进程(多pVM)应用程序,其所有进程(pVM)都在OS(Hypervisor)上协同运行。目前,KylinX遵循严格的隔离模型[67],其中只有相互信任的pVM才能相互通信,这将在第3.2.3中详细讨论。

两个通信pVM使用事件通道共享页面来实现pVM间通信。如果两个相互信任的pVM在第一次通信时尚未初始化事件通道,因为它们没有通过fork()产生的父子关系(3.2.1),那么KylinX将:

  • 验证其相互适应性(第3.2.3节,必须是一个family的)
  • 初始化事件通道
  • 在它们之间共享专用页面。

事件通道用于通知事件,共享页面用于实现通信。 KylinX已经实现了以下四种类型的inter-pVM通信API(在表2中列出)。

  • (1)pipe(fd)创建一个管道并返回两个文件描述符(fd [0]和fd [1]),一个用于写入,另一个用于读取。
  • (2)kill( domid,SIG )通过将SIG写入共享页面并通知目标pVM(domid)从该页面读取信号,将信号(SIG)发送到另一个pVM(domid); exit和wait是使用kill实现的。
  • (3) ftok( path,projid)将path和proj id转换为IpC密钥,这将由msgget(key,msgflg)用于创建带有标志的消息队列(msgflg)并返回队列ID(msgid); msgsend (msgid,msg,len)和msgrcv(msgid,msg,len)使用长度len写入/读取队列(msgid)到/来自msmbuf结构(msg)。
  • (4)shmget(key,size,shmflg)使用键(key),内存大小(size)和flag(shmflg)创建并存储一个内存区域,并返回共享内存区域ID(shmid),它可以附加和分离到shmat(shmid,shmaddr,shmflg)和shmdt(shmaddr)。

3.2.3 动态页面映射限制

在执行动态pVM fork时,父pVM将页面分享给空的子pVM ,该过程不会引入新的威胁。

在执行IpC时,KylinX通过抽象相互信任的pVM 来保证安全性,这些pVM是从同一个根pVM分叉的。例如,如果pVM A分支pVM B,它进一步分叉另一个pVM C,那么三个pVM A,B和C属于同一个家庭。为简单起见,目前KylinX遵循all-all-nothing隔离模型:只有属于同一系列的pVM才被认为是可信的并且允许彼此通信。 KylinX拒绝不受信任的pVM之间的通信请求。

3.3 动态库映射

3.3.1 pVM库链接

继承自MiniOS,KylinX具有单个平面虚拟存储器地址空间,其中应用程序二进制和库,系统库(用于引导程序,内存分配等)和数据结构共同定位以运行。 KylinX将一个动态段加入MiniOS的原始内存布局中,以便在加载后适应动态库。

如图2所示,我们在Xen控件库(libxc)中实现了动态库映射机制,它由上层工具栈使用,例如xm/xl/chaos。 pVM实际上是一个准虚拟化domU,它

  • 创建一个域,
  • 解析kernel image文件
  • 初始化启动内存,
  • 在内存中构建映像
  • 启动映像的domU。

在上面的第4步中,我们通过扩展libxc的静态链接过程,添加一个函数(xc_dom_map_dyn())来将共享库映射到动态段中,如下所示。

  1. 首先 ,KylinX从设备映像的程序头表中读取共享库的地址,偏移量,文件大小和内存大小。
  2. 第二 ,它验证是否满足限制(第3.3.4节KylinX强制限制库的身份以及库的加载器)。 如果不是,则程序终止。
  3. 第三 ,对于每个动态库,KylinX检索其 动态部分的信息,包括动态字符串表,符号表等。
  4. 第四 ,KylinX将整个依赖树中的所有必需库映射到pVM的动态段,当实际访问时,它将惰性地将未解析的符号重定位到正确的虚拟地址。
  5. 最后 ,它跳转到pVM的入口点。

KylinX在实际使用之前不会加载/链接共享库,这类似于传统进程的延迟绑定[ 17]。因此,KylinX pVM的启动时间低于以前的Unikernel VM。 此外,与之前仅支持静态库的Unikernel相比,使用共享库的KylinX的另一个优势是它有效地减少了高密度部署中的内存占用(例如,LightVM [58]中的每台机器8K VM和每台机器80K容器)在Flurries [71]中,这是限制可扩展性和性能的唯一最大因素[58]。

【Mark:动态链接和延迟绑定:www.jianshu.com/p/20faf72e0…

接下来,我们 将讨论KylinX AVM的动态库映射的两个简单应用。

3.3.2 在线 pVM库更新 保持系统/应用程序库的最新版本以修复错误和漏洞非常重要。 静态Unikernel [56]必须重新编译并重新启动整个设备映像才能为其每个库应用更新 ,这可能会导致设备拥有许多第三方库时出现大量部署负担。

在线库更新比滚动启动更有吸引力,主要是保持与客户端的连接。首先,当服务器有许多长期连接时,重新启动将导致高重新连接开销。其次,不确定第三方客户端是否会重新建立连接,这会在重新启动后为重新连接施加复杂的设计逻辑。第三,频繁重启和重新连接可能会严重降低关键应用程序的性能,如高频交易。

动态映射使KylinX可以实现在线库更新。 但是,库可能有自己的状态,例如压缩或加密,因此简单地替换无状态函数不能满足KylinX的要求。

像大多数库更新机制(包括DYMOS [51],Ksplice [29],Ginseng [61],PoLUS [37 ],Katana [63],Kitsune [41]等),KylinX要求新旧库与二进制兼容:允许向库中添加新函数和变量,但不允许更改函数接口,删除函数/变量或更改结构字段。对于库状态,我们期望所有状态都存储为在更新期间将被保存和恢复的变量(或动态分配的结构)。

KylinX提供了更新(domid,new_lib,old_lib)API,可以动态地将old_lib和new_lib替换为domU pVM(ID = domid),并具有必要的库状态更新。 我们还提供了一个更新命令“update domid,new_lib,old_lib” 用于解析参数并调用update() API。

动态pVM更新的难点在于在密封的VM设备中操作符号表。 我们利用dom0来解决这个问题。 当调用更新API时,dom0将 (i)将新库映射到dom0的虚拟地址空间; (ii)与domU共享装载的库; (iii)通过要求domU检查domU的每个内核线程的调用堆栈来验证旧库是否静止; (iv)等到旧库未被使用并暂停执行; (v)将受影响的符号条目修改为适当的地址; 最后 (vi)释放旧库。 在上述第五步中,有两种符号(函数和变量)将如下所述进行解析。

函数。 函数的动态解析过程如图4所示。我们将重定位表,符号表和字符串表保存在dom0中,因为它们不在可加载段中。 我们在dom0中加载全局偏移表函数(.got.plt )和过程链接表(.plt)并与domU共享它们。 为了在不同的域中解析符号,我们在.plt 表的第1st个条目中修改了2nd的汇编行 (如图4中的蓝色区域所示),以指向KylinX的符号解析函数(du_resolve)。 在加载新的库(new_lib)之后,将old_lib中的每个函数输入 .got.plt表(例如,图4中的foo)被修改为指向.plt表中的相应条目,即图4中虚线绿线所示的2nd组件(push n)。当一个函数(在new_lib加载后第一次调用库的foo),将使用两个参数( n (got + 4)) 调用du_resolve ,其中n是.got.plt表中符号(foo)的偏移量和(got+ 4)是当前模块的ID。 然后du_resolve要求dom0调用对应的d0_resolve,它在new_lib中找到foo,并将当前模块的gt.plt表中的相应条目(由n定位)更新为foo的正确地址(图中的蓝线) 4)。

变量。 变量的动态分辨率略微复杂。 目前我们只是假设new_libexpect将其所有变量设置为它们的实时状态inold_lib而不是它们的初始值。 如果没有这个限制,编译器将需要扩展以允许开发人员为每个变量指定他们的意图。

(1)全局变量。 如果在主程序中访问了库的全局变量(g),则g存储在程序的数据段 (.bss )中,并且在指向g的库的全局偏移表(.got)中存在条目,因此加载new_lib后,KylinX会将new_lib的.got表中的g条目解析为g的正确地址。 否则,g存储在库的数据段中,因此KylinX负责将全局变量g从old_lib复制到new_lib。

(2)静态变量。 由于静态变量存储在库的数据段中并且无法从外部访问,因此在加载new_1 ib之后,KylinX将简单地将它们从old_lib逐个复制到new_lib。

(3)指针。 如果库指针(p)指向动态分配的结构,那么KylinX会预先设置结构并将new_lib中的p设置为它。 如果p指向存储在程序数据段中的全局变量,那么p将从old_lib复制到new_lib。 如果指向静态变量(或存储在库中的全局变量),则p将指向新地址。

3.3.3 pVM 回收

KylinX pVM和Unikernel VM [58]的标准启动(第3.3.1节)相对较慢。 正如评估的第4章所述,启动pVM或UnikernelVM需要100多毫秒,大部分时间用于创建空域。 因此,我们为KylinX pVM设计了一个pVM回收机制,利用动态库映射来绕过域创建。

回收的基本思想是重用一个内存空域来动态地将应用程序(作为共享库)映射到该域。 具体来说,在调用占位符动态库的app_entry函数之前,会检查一个空的可回收的域并等待运行应用程序。使用app_entry作为条目,将应用程序编译为共享库而不是可引导映像。为了加速应用程序的pVM引导,KylinX恢复了被检查的域,并通过在在线更新过程之后替换占位符库来链接应用程序库(第3.3.2节)。

3.3.4 动态库映射限制

与执行动态库映射时静态和单片密封的Unikernel相比,KylinX应该隔离任何新的漏洞。 主要的威胁是攻击者可能会将恶意库加载到pVM的地址空间,用具有相同名称和符号的受损库替换库,或者将共享库的符号表中的条目修改为伪符号/函数。

***【Linux进程地址空间学习: ***

http://www.choudan.net/2013/10/24/Linux%E8%BF%9B%E7%A8%8B%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4%E5%AD%A6%E4%B9%A0***(%E4%B8%80).html******】***

为了解决这些威胁,KylinX强制限制库的身份以及库的加载器。 KylinX支持开发人员指定动态库的签名,版本和加载器的限制,这些限制存储在pVM映像的标头中,并在链接库之前进行验证。

**签名和版本。**库开发人员首先生成库的SHA1摘要,该摘要将由RSA(Rivest-Shamir-Adleman)加密。 结果保存在动态库的asignature部分中。 如果设备需要对库进行签名验证,则KylinX将使用公钥读取并验证签名部分。同样要求并验证版本限制。

装载机。 开发人员可以在库的加载器上请求不同级别的限制:(i)仅允许pVM本身作为加载器; (ii)还允许同一申请的其他pVM; 或(iii)甚至允许其他应用程序的pVM。 通过前两个限制,一个受损应用程序中的恶意库不会影响其他应用程序。 加载程序检查的另一种情况是将应用程序二进制文件作为库并将其链接到pVM以进行快速回收(第3.3.3节),其中KylinX将加载程序限制为空pVM。

有了这些限制,与静态密封的Unikernel相比,KylinX没有引入任何新的威胁。 例如,pVM的运行时库更新(第3.3.2节)对签名(作为可信开发人员 ),版本 (作为特定版本号)和加载器(作为pVM本身)具有限制,将具有相同的级别安全保障重新编译和重新启动。

4 评估

我们在Ubuntu 16.04和Xen上实现了KylinX的原型。 按照MiniOS [14]的默认设置,我们分别使用RedHat Newlib和1wIP作为libc/libm库和TCP/IP堆栈。我们的试验台有两台机器,每台机器都配有Intel 6 core Xeon ES-2640 CPU,128 GB RAM和一台1 Gb ENIC。

我们已经向KylinX移植了一些应用程序,其中我们将使用多进程Redis服务器[13]以及多线程Web服务器[11]在4.6章中来评估KylinX的应用程序性能。 由于MiniOS和RedHat Newlib的限制,目前需要进行两种调整才能将应用程序移植到KylinX。 首先,KylinX只能支持select而不是更高效的epoll。 其次,进程间通信(IPC)仅限于表2中列出的API。

4.1 标准启动

我们评估 KylinX pVM 的标准启动过程( 3.3.1)的时间,并将其与所有运行Redis服务器的MiniOS VM和Docker容器进行比较。 Redis是一个内存中的键值存储,支持快速键值存储/查询。 每个键值对由固定长度键和可变长度值组成。它使用单线程进程来提供用户请求,并通过分配新的备份过程来实现(定期)序列化。

我们禁用Xen Store日志记录以消除定期日志文件刷新的干扰。RedHat Newlib的C库(libc)在嵌入式系统中是静态的,很难转换为共享库。简单来说,我们将libc编译成静态库和libyn( Newlib的数学库)到一个共享库中,该库将在运行时链接到KylinX pVM。由于Mini不能支持fork,我们(暂时)删除此实验中的相应代码。

启动单个KylinX pVM大约需要124毫秒,可以大致分为两个阶段,即在内存中创建域/映像(步骤1~4,第3.2.1节),以及引导映像(步骤5)。动态映射在第一阶段执行。大多数 时间(大约121毫秒)花费在第一阶段,这会调用高级调用来与Hypervisor进行交互。第二阶段启动pVM大约需要3毫秒。在此相反,MiniOS大约需要133毫秒启动一个虚拟机,而Docker 需要花费约210毫秒开始建立容器。 KylinX比MiniOS花费的时间更短,主要是因为在引导期间不会读取/链接共享库。

然后,我们评估在一台机器上顺序启动大量(最多1K)pVM的总时间。我们还评估了MiniOS VM和Docker容器的总启动时间,以便进行比较。

结果如图5所示。首先,由于延迟加载/链接,KylinX比MiniOS快得多。其次,MiniOS和KylinX的启动时间随着VM/pVM数量的增加而线性增加,而Docker容器的启动时间只是线性增加,这主要是因为XenStore在服务大量的VM/pVM时效率很低。

4.2 fork和回收

与容器相比,由于XenStore效率很高,KylinX的标准启动无法很好地扩展到大量pVM。最近,LightVM [58]通过实现chaos/libchaos,noxs(无XenStore)和拆分工具堆栈以及许多其他优化来完全重新设计Xen的控制平面,从而实现大量VM的ms级启动时间。我们采用LightVM的nox来消除XenStore的影响,并测试运行未经修改的Redis仿真传统进程分支的pVM fork机制。 LightVM的noxs使KylinX pVM的启动时间即使对于大量pVM也能线性增加。单个pVM的fork大约需要1.3毫秒(未显示缺少空间),比LightVM的原始启动过程快几倍(约4.5毫秒)。KylinX pVM 的fork比 Ubuntu上的进程fork(大约1 ms)略慢,因为包括页面共享和参数传递在内的多个操作非常耗时。请注意,父/子pVM的事件通道和共享页的初始化是异步执行的,因此不计入fork的延迟。

4.3 内存占用

我们在一台机器上测量不同数量的pVM/VM/容器的KylinX,MiniOS和Docker(Running Redis)的内存占用量。结果(如图6所示)证明,与静态密封的MiniOS和Docker容器相比,KylinX pVM具有更小的存储空间。这是因为KylinX允许同一个应用程序( 第3.3章) 的所有设备共享库(libc除外),因此共享库最多需要加载一次。内存占用优势促进了虚拟化[42],可用于在VM设备之间动态共享物理内存,并使KylinX能够实现与页面级重复数据删除[40]相当的内存效率,同时降低复杂性。

4.4 Inter-pVM通信

我们通过分配父pVM并测量父/子通信延迟来评估pVM间通信(IpC)的性能。我们将一对父/子pVM称为线性pVM。正如引言第3.2.1节所述,两个线性pVM已经有一个事件通道共享页面,因此它们可以直接与其他页面进行通信。相反,非线性pVM对必须在第一次通信之前初始化事件通道和共享页面。

结果列于表3中,我们将其与Ubuntu上相应的IPC进行比较。由于Xen的高性能事件通道和共享内存机制,两个线性pVM之间的KylinX IpC延迟与Ubuntu上相应的IPC延迟相当。请注意,pipe的延迟不仅包括创建管道,还包括通过管道写入和读取值。由于初始化成本的原因,非线性pVM之间的首次通信延迟要高出几倍。

4.5 运行时库更新 我们通过使用较新版本(RedHat Newlib 1.18)动态替换默认libyn(RedHat Newlib 1.16)来评估KylinX的运行时库更新。libyn是MiniOS / KylinX使用的数学库,包含110个基本数学函数的集合。

为了测试KylinX对全局变量的更新过程,我们还向旧的和新的libyn库添加了111个伪全局变量以及一个read_global函数(读出所有全局变量)。主函数首先将全局变量设置为随机值,然后通过调用读取全局函数定期验证这些变量。

因此,在我们的测试中总共有111个函数和111个变量需要更新。更新程序大致可分为 4个阶段,我们测量每个阶段的执行时间。

首先,KylinX将new_lib加载到dom0的内存中并与domU共享。其次,KylinX修改.got.plt表中函数的相关条目,以指向.plt表中的相应条目。 第三,KylinX 为每个函数调用du_resolve,这些函数要求dom0解析给定的函数并返回其在new_lib中的地址,然后将相应的条目更新为返回的地址。最后,KylinX将新lib的.got表中的全局变量的相应条目解析为适当的地址。我们在评估中修改第三阶段,一次更新libyn中的所有111个函数,而不是在实际被调用时懒惰地链接函数(第3.3.2节),以便概述libyn的整个运行时更新成本。

结果如图7所示,其中更新所有函数和变量的总开销约为5毫秒。第三阶段(解析函数)的开销高于其他阶段,包括第四阶段(解析变量),这是由第三阶段中的几个耗时的操作引起的,包括解析符号,跨域调用d0_ resolve,返回实际函数地址和更新相应的条目。

4.6 申请

除了pVM调度和管理的流程灵活性和效率之外,KylinX还为其容纳的应用程序提供了高性能,与Ubuntu上的对应应用程序相当,如本小节所述。

4.6.1 Redis 服务器应用程序

我们在KylinX pVM中评估Redis服务器的性能,并将其与MiniOS/Ubuntu中的性能进行比较。同样,由于MiniOS不支持fork(),我们暂时删除了序列化代码。 Redis服务器使用select而不是epoll来实现异步I/O,因为 MiniOS和KylinX使用的lwIP堆栈[4]尚不支持epoll。

我们使用Redis基准[13]来评估性能,该性能使用可配置数量的繁忙循环来异步写入KV。我们为客户端的写请求运行不同数量的pVM/VM/进程(1个服务器一个)。我们测量写入吞吐量作为服务器数量的函数(图8)。三种Redis服务器具有相似的写入吞吐量(由于选择的限制),随着并发服务器的数量几乎线性增加(在lwIP堆栈成为瓶颈之前,缩放是线性的,最多8个实例)。

4.6.2 Web 服务器应用程序

我们评估了KylinX中的JOS Web服务器[11],它为多个连接提供多线程处理。主线程接受传入连接后,Web服务器创建工作线程来解析标头,读取文件,并将内容发送回客户端。我们使用Weighttp基准测试来支持HTTP协议的一小部分(但对我们的Web服务器来说足够)来衡量Web服务器性能。与Redis服务器的评估类似,我们通过在一台计算机上运行多个Weighttp [8]客户端来测试Web服务器,每个客户端不断向Web服务器发送GET请求。

我们将吞吐量作为并发客户端数量的函数进行评估,并将其与分别在MiniOS和Ubuntu上运行的Web服务器进行比较。结果如图9所示,其中KylinX web服务器实现了比MiniOS web服务器更高的吞吐量,因为它提供更高的顺序性能。KylinX和MiniOS Web服务器都比Ubuntu Web服务器慢,因为异步选择是使用MiniOS的网络驱动程序[27}进行低效调度的。

5 相关工作

KylinX与静态Unikernel设备[56,27 ],减少 VM [ 19,48,49 ],容器[66,9,15]和图像处理[38,62,32,54,67,33]有关。

5.1 Unikernel 和Redced VMs

KylinX是Unikernel[56]的扩展,在MiniOS [27]之上实现。Unikernel OS包括Mirage [56],Jitsu [55],Unikraft [18]等。 例如,Jitsu [55]利用Mirage [56]设计一个功能强大且响应迅速的平台,用于在边缘网络中托管云服务。LightVM [58]利用Xen上的Unikernel来实现快速启动。

MiniOS [27]设计并实现了一个C风格的Unikernel LibOS,它作为Xen域中的半虚拟客户OS运行。MiniOS具有比Mirage更好的向后兼容性,并支持用C语言编写的单进程应用程序。但是,最初的MiniOS静态密封设备并且遇到与其他静态Unikernel相似的问题。

KylinX和静态 Unikernels( 如Mirage [56],MiniOS [27]和EbbRT [65])之间的区别在于pVM抽象,它明确地将hypervisoras作为操作系统并支持过程式操作,如pVM fork/IpC和动态库映射。映射限制(第3.3.4节)使KylinX尽可能地引入漏洞,并且没有比 Mirage/MiniOS 更大的TCB [56,55]。 KylinX支持源代码(C)兼容性,而不是使用类型安全的语言来重写整个软件堆栈[56]。

最近的研究 [19,49,48]试图改进基于Hypervisor的类型1虚拟机,以实现更小的内存占用,更短的启动时间和更高的执行性能。 Tiny Core Linux [19]尽可能减少现有的Linux发行版,以减少客户的开销。 0S0 [49]实现了一个新的客户操作系统,用于在VM上运行单个应用程序,解析对其内核的libc函数调用,该内核采用优化技术,如spinlock-freemutex [70]和网络通道网络堆栈[46 ] .RumpKernel [48]通过实现优化的客户操作系统来减少VM。与KylinX不同,这些通用LibOS设计包含针对目标应用的不必要的特征,导致更大的攻击面。它们不支持多进程抽象。此外,KylinX的pVM fork比SnowFlock中基于重复的VM_fork要快得多[50]。

5.2 容器

容器使用操作系统级虚拟化[66]和利用内核功能来打包和隔离进程,而不是依赖于虚拟机Hypervisor。作为回报,他们不需要捕获系统调用或模拟硬件,并且可以作为正常的OS进程运行。例如,Linux Containers(LXC)[9]和Docker [15]通过使用许多Linux内核功能(例如naynespaces和cgroups)来创建容器,以打包资源并运行基于容器的进程。

容器需要使用相同的主机操作系统API [49],从而暴露数百个系统调用并扩大主机的攻击面。因此,尽管LXC和Docker容器通常比传统VM更有效,但它们提供的安全性较低,因为攻击者可能会破坏容器内运行的进程。

5.3 Picoprocess

picoprocess本质上是一个容器,它在主机操作系统和客户机之间实现LibOS,将高级客户机API映射到一个小接口上。原始的picoprocess设计(Xax [38]和Embassies [43])只允许一个微小的系统调用API ,它可以小到令人信服(甚至可以证实)的孤立。 Howell等。通过提供POSIX 仿真层并绑定现有程序,展示如何在最小的picoprocess接口[44]之上支持一小组单进程应用程序。

最近的研究放松了静态和刚性微过程隔离模型。。例如,Drawbridge [62]是Xax [38] picoprocess的WinBows转换,并创建了支持丰富桌面应用程序的picoprocess LibOS。 Graphene [67]扩展了LibOS范式,支持在picoprocesses的一个家族(沙箱)中使用多进程API(使用消息传递)。 Bascule [ 32]允许 在运行时安全有效地附加与OS无关的扩展。 Tardigrade [54]使用picoprocesses轻松构建容错服务。这些松弛在picoprocess上的成功激发了我们对Unikernel的动态KylinX扩展。

容器和picoprocesses通常具有大的TCB,因为LibOS包含未使用的功能。相比之下,KylinX和其他Unikernel利用虚拟机Hypervisor的虚拟硬件抽象来简化它们的实现,并遵循极简主义[36]仅将应用程序与必需的库相结合,不仅提高了效率,还提高了安全性。

Dune [34]利用Intel VT-x [69]提供进程(而不是机器)抽象来隔离进程并访问特权硬件功能。IX [ 35]将 虚拟设备整合到Dune过程模式中,为网络系统实现了高吞吐量和低延迟。1wCs [53]在进程内提供独立的保护,特权和执行状态单元。

与这些技术相比,KylinX直接运行Xen(1型虚拟机Hypervisor),自然提供强大的隔离,使KylinX能够专注于灵活性和效率问题。

6 结论

在云虚拟化的文献中,长期存在强烈孤立和丰富特征之间的紧张关系。本文利用新的设计空间,通过在高度专用的静态Unikernel中添加两个新特性(动态页面和库映射)来提出pVM抽象。简化的虚拟化架构(KylinX)将虚拟机Hypervisor作为OS,并安全地支持灵活的进程式操作,例如pVM fork和inter-pVM通信,运行时更新和快速回收。

在未来,我们将通过模块化[27],分解[60]和新交所飞地[33,28,45,68] 来提高安全性。我们将通过采用更高效的运行时MUSL来改善KylinX的性能[23],并使KylinX适应Multi LibOS model [65],允许将pVM跨越多个机器。目前,pVM的回收机制还是暂时的和有条件的:它只能检查点的空域; 循环的pVM无法使用事件通道或共享内存与其他pVM通信; 应用程序只能采用自包含共享库的形式,不需要加载其他共享库; 回收后,新老pVM之间仍然没有检查潜在安全威胁的保障措施。我们将在未来的工作中解决这些缺点。

7 致谢

这项工作得到了中国国家基础研究计划(2014CB340303)和国家自然科学基金(61772541)的支持。Wethank Li Ziyang Li,Qiao Zhou和匿名评论员帮助他们完善了本文。这项工作是在第一作者访问剑桥大学计算机实验室的NetOS小组时进行的,我们感谢Anil Madhavapeddy 教授,Ripduman Sohan和刘浩的讨论。

正文之后

搞掂,希望有用吧。。这些新点的文章网络上屁内容都没得,国防科技大学的老师也没得对外的联系方式,所以说,选了这篇文章做汇报的同学,加油~