本文主要是介绍【论文笔记】想自己重构操作系统吗?学学 Drawbridge 吧 —— 沙箱机制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
本文目标:精度论文 “Rethinking the Library OS from the Top Down” 。
(弃坑,但主旨应该讲清楚了,ε=ε=ε=( ̄▽ ̄))
该论文于2011年发布在ACM上,提出了 Drawbridge 沙箱机制,有不少最新研究以此机制为基础进行扩展,但,你知道这一机制不过是老调重弹吗?这里可能没有多新颖的技术,但有值得学习的思想,有更全面的操作系统架构知识,如果你也在学习操作系统的路上,或许这篇文章可以带给你想要的哦~
全文一览
- 第一个脚印:重新审视 Library OS 的旧方法。
- 第二个脚印:对于 Windows 7 ,你得知道这些!
- 第三个脚印:Drawbridge 在 Windows 7 上做了什么?(简述)
- 第四个脚印:开始具体重构吧!
- 第五个脚印:关门,放代码!
- 第六个脚印:万众期盼的 Drawbridge 测评
当一个完整的 商业操作系统 被重新设计为一个能够运行重要应用程序的 Library OS(库操作系统) 时,是否能更好地保护系统完整性和快速系统演化?
作者希望它能够实现 VMM 的优势,并且降一个数量级的开销。全文主要介绍一个名为 Drawbridge 的 Windows 7 Library OS ,贡献简述:
-
Drawbridge 是史无前例的重构——将广泛使用的单片操作系统(Windows 7)重构为一个功能丰富的库操作系统(Library OS)。
-
新型 ABI —— 从 host OS 中分离出 Library OS 的新 ABI ,增强应用程序的可移植性。
-
这个 Drawbridge 上可以运行大量最新商业版本的应用程序,包括 Microsoft Excel 、PowerPoint 、Internet Explorer 和 IIS 。
-
自顶向下构建 Library OS ,优先考虑应用程序兼容性和高级操作系统代码重用,避免 Library OS 对底层硬件进行低级管理。
-
运行在 Drawbridge 上的 Windows 应用程序可以访问 Windows 的核心特性和增强的 API ,包括 .NET 公共语言运行库(CLR)和 DirectX 。
-
Library OS 和 host OS kernel 之间由一个小型抽象固定集连接,也就是说,Library OS 与底层内核组件相独立。(小型抽象固定集:线程、虚拟内存、I/O流)
-
Drawbridge应用程序通过网络协议重用跨独立 Library OS 实例,可以实现资源共享。(资源:屏幕、键盘、鼠标和用户剪贴板)
-
Drawbridge 可以以很小的开销解决当前许多硬件虚拟机的使用。
-
Drawbridge 重构了客户操作系统,只提取应用程序需要的 API ,并且它仅增加了不到16MB的工作集和64MB的磁盘。
-
Drawbridge采用VMM方法,对应用程序和 OS 单独打包,最小化与底层硬件的依赖性,运用服务器整合和云计算技术,增强程序的可移植性。
(原文:Drawbridge方法可以对独立应用程序进行细粒度的打包,从而对桌面计算产生重大影响。VMM方法允许构建由应用程序和操作系统组成的独立应用程序包,对底层VMM或硬件的依赖性最小。基于VMM的应用程序打包,通过服务器整合和云计算,实现了服务器计算的巨大转变,尽管这一切都会带来巨大的开销。更细粒度、更高性能的应用程序以及可能带有 Library OS 的操作系统包 或许会使得桌面和移动计算发生类似转变,比方说,运行中的 Drawbridge 应用程序的快照可以很容易地从一个设备移动到另一个设备,并移动到云上,因为它们非常小—— Drawbridge 中的 Excel 的压缩进程快照小于4MB,而类似的VM快照则接近150MB。) -
这种设计的好处包括:
1)从 Library OS 强封装 host OS ,实现每个 OS 的快速独立演化;
2)跨计算机迁移单个应用程序的运行状态;
3)更好地保护系统和应用程序的完整性(即强隔离进程)。
基本就这些内容啦~
第一个脚印:重新审视 Library OS 的旧方法。
- Library OS 的理念可以理解为:将每个应用程序所依赖的 OS(操作系统) 的 personality(特性) 作为 library(库) ,使其独立地运行在该应用程序的地址空间上。
- 所谓 OS 的 personality 是指:OS 的 API(应用程序编程接口) 和 应用程序可见语义 的实现;应用程序在其上构建OS服务。
Library OS 早期的支持者认为,通过个性化定制每一个应用程序,足以实现OS较好的性能。
但如今,Library OS 方法似乎被遗忘了,它成为了 现代虚拟机监视器(VMM)崛起的牺牲品。
要理解这个说法,首先要清楚一个大背景。包括 Library OS 在内,当年的很多操作系统设计都有一个共同的问题——在小型机上仅能运行一小部分定制的应用程序。这很麻烦,所以 兼容性 便成为人们当时最迫切的需求。
然而这时人们发现,在只有一台计算机硬件的情况下,VMM 能够通过虚拟化技术重用多个操作系统,并且让这些操作系统都自以为独占了整个硬件,这正是我们需要的!由此,VMM 盛极一时。
Library OS 的系统设计固然有优秀之处,却也未能胜过那个时代对兼容性的需求,再加上自20世纪90年代以来,互联网的兴起使得人们对安全性和独立系统隔离的需求增加,大家都忽视了对 Library OS 的研究,只能说 Library OS “生”错了时代。
那为什么今天又重谈这一方法呢?先举个例子:当I/O磁盘绑定具有特殊文件访问模式的应用程序时,如果使用自定义文件系统存储堆栈,那么其性能会比使用默认顺序预取的启发式方法更好。 (不太理解)
总的来说,我们主要是出于对个性化应用程序 性能 的考虑,我们青睐于 Library OS 的性能,但其不兼容、控制粗粒度等弊端又是我们头疼的地方,具体表现在 Library OS 的低级硬件抽象暴露。有很多学者从控制粒度上下手,希望通过更细粒度地控制应用程序的硬件资源(如页表、网络数据包和磁盘块),来解决低级硬件抽象暴露问题,这种思考方式使得操作系统更加地复杂繁琐。
显然低级硬件抽象不好控制,那高级抽象会更容易一些吗?既然要重新审视 Library OS 的旧方法,那么就要优先考虑这些年演化的 应用程序兼容性、安全隔离 以及 系统独立性 的优势。
不考虑低级硬件抽象暴露,仅模仿 VMM 的虚拟化机制去解决兼容问题。这一思路是使用 VMM设备 将 传统OS 直接虚拟化为 Library OS ,但其产生的开销实在太大了,因为不同的 专用VM 都需要虚拟一个独立的 OS 来运行某个应用程序的副本,而这些大量的 OS 运行会伴随着巨大的存储开销。就拿 Hyper-V VM 来说,运行一个 Windows 7 客户端操作系统就需要占用 512MB的内存(RAM)空间 和 4.8GB的磁盘(disk)空间 ,性能反而不好了。
重点来了!作者提出在功能丰富的现代商业 OS 上构建一个可以运行主要应用程序的 Library OS —— Windows 7 Library OS —— Drawbridge 。他结合了 VMM 的虚拟化思想,让 Library OS 的每个 personality 都去共享底层 host OS 资源(如缓冲区缓存、文件系统和网络工作栈),这样一来,只需提取某应用程序所需要的 API 即可,相比于虚拟化整个 OS ,这种方式无疑会大大降低其开销。
旧方法不一定要全盘否定,我们都站在巨人的肩膀上,只要取其精华、去其糟粕,用新思想重构旧方法,遇见的就是新世界。
第二个脚印:对于 Windows 7 ,你得知道这些!
Windows 架构:DLL + services + NT kernel + drivers(不管怎么说,架构总得了解一下吧)
-
DLL (dynamic link libraries):一个含代码和数据的 动态链接库 ,可由多个程序同时使用,会加载到应用程序的地址空间中。 <类比>Unix系统的共享对象文件(.so文件)
-
services :作为守护进程运行的 服务 。
-
NT kernel :是动态加载的内核模式组件。它实现了 单片操作系统的核心 :资源管理、调度、I/O服务、层次对象名称空间和注册表(用于配置数据的键值存储)。
-
drivers :是动态加载的内核模式组件。一般地, 可替换内核模式组件 (如网络堆栈和文件系统)会被加载为驱动程序。
DLL 可以访问 NT kernel(内核) 吗?可以通过 runtime DLL 、ntdll 间接访问。
ntdll 是内核在创建过程中插入到每个进程中的,它不仅实现 DLL 的动态加载程序,还会实现类似于 Unix libc 的功能(包括 NT系统调用表 中 401函数 的 stub )
libc 一般特指某个操作系统的标准库
一个常识,DLL文件的调用有两种方式。
- 利用 .h 、.lib 和 .dll 三个文件在项目中调用动态链接库。
- 利用 Win32 的 API 来对动态链接库进行调用。
在本文中,作者主要介绍了第二种方式,它的原理在于:所有的 Windows 应用程序都会被编程为 Win32 API ,因此,Win32 将包含超过 100,000 个 API 函数,而 API 则会被实现为 进程内DLL 的大型集合。
常用的 Win32 API DLL 有:
- kernel32:它提供对内核操作的访问,以实现 进程控制、线程、虚拟内存、注册表 以及 块和字符设备I/O功能 ;
- user32和gdi32:它们提供了窗口、绘图和 GUI 的基础;
- ws2_32:它为网络堆栈提供套接字接口;
- ole32:它提供对 组件对象模型(COM) 和 对象链接与嵌入(OLE) API 的访问,以构建多组件应用程序实例(例如,带有 嵌入式Excel图表 的 PowerPoint演示文稿 )。
这些 DLL 相当于像 libX11 这样的库,以及 Unix系统 上构建的 GNOME框架 或 KDE框架 的库。
上面提到的 Win32 是什么呢?Win32 是指 Microsoft Windows 操作系统的 32位 环境。在 Windows 子系统中可以实现 Win32 的核心: win32k(内核模式组件) 和 csrss(用户模式守护程序) 。
- win32k :驻留在此处的实现较多,包括 窗口事件消息队列 、重叠窗口 、光栅化 、字体管理和渲染 、鼠标和键盘输入事件队列 以及 共享剪贴板 的实现。
- csrss :它协调 系统初始化、关闭 和 应用程序错误报告 。
- 在 Windows NT 4.0(1996) 之前,win32k 中现存功能会运行在 csrss 服务守护进程中,后来这些功能被移动到内核模式中,用以提高 性能 ,简化 加速图形驱动程序 的实现。
- 用户模式 API DLL 通过 user32和di32 中的 stub 间接访问 win32k ; stub 存在于 win32k 的 827 个函数的辅助系统调用表中。
除了 Windows 子系统之外,Win32 API 的实现还依赖于多个服务守护进程。
- smss 类似于 Unix init ,处理启动和关闭。
- wininit 创建只读共享数据结构,这些结构随后映射到大多数进程中,并由 win32k 用于缓存诸如默认字体、国际化表和游标等常见对象。wininit 还可以在登录时启动用户桌面的组件,类似于X会话管理器。
- rpcss 实现了用于高级进程间通信的共享服务,包括 COM 和 OLE 、 类似于 Linux 中的 D-Bus 、 explorer 、 Windows GUI shell、 启动程序并为 drag-and-drop 提供共享服务、“打开”和“保存”对话框,以及文件预览。
- dwm 实现 Windows 7 合成窗口管理器
差不多了解到这里就可以了,你是不是也迫不及待地想知道作者在 Win7 架构上做了啥!
第三个脚印:Drawbridge 在 Windows 7 上做了什么?(简述)
首先要明白一个结构化原则。在操作系统的实现中有三类服务:硬件服务 、用户服务 和 应用服务 。
-
硬件服务 hardware services,包括操作系统内核、设备驱动程序、文件系统和TCP/IP网络堆栈,其中操作系统内核和设备驱动程序用于抽象和多路传输的硬件。
-
用户服务 user services,包括GUI shell、桌面、剪贴板、搜索索引器等。(GUI:图形用户界面)
-
应用服务 application services,包括 API实现 、框架 、渲染引擎 、通用UI控件 、公共语言运行时 等。对于一个应用程序来说,这些 API 组成了 OS 的 personality 。
应用程序 与 应用服务 通信,而 应用服务 又与 硬件服务 和 用户服务 通信。
直接上图:(浅灰-用户服务、白色-应用服务、深灰-硬件服务)
记住这个框架图!现在使用这些服务,把 重构的Windows 放进 Drawbridge Library OS 里去。
- 将 应用服务 打包到 Library OS 中,而 用户服务 和 硬件服务 则被留在 host OS 中。
出现两个 OS !那么现在这些服务之间要怎么通信呢? Drawbridge 提供了一个 ABI(应用程序二进制接口)。
-
由 ABI 的 平台适配层(platform adaptation layer) 和 安全监视器(security monitor) 来实现 Library OS 中的 应用服务 与 host OS 中的 硬件服务 之间的通信;
-
由 ABI 中的 RDP(远程桌面协议) 来实现 Library OS 中的 应用服务 与 host OS 中的 用户服务 之间的通信。
重构的架构:( ABI 、RDP 都独立于 host OS )
好,Drawbridge 架构图已经定制出来了,可看起来更复杂了,所以作者大费周章的划分出独立的 Library OS 到底是想做什么呢?
前面提到要重新审视 Library OS 的旧方法,就要优先考虑 应用程序兼容性、安全隔离 以及 系统独立性 的优势,所以作者希望 每个应用程序都能有其自身的 Library OS 副本 ,前面提到模仿VMM,利用虚拟化技术,让每个 Library OS 都自以为独占了整个资源,以解决其兼容性问题,这一点在 Drawbridge 上是如何实现的呢?
-
安全监视器 强制实施一组外部策略,以管理应用程序可用的 host OS 资源。
-
Library OS 的 ABI ,以最少的重复工作虚拟化一套 host OS 资源,将其公开给 library OS ,并在 host OS 不同的实现中维护一组统一的抽象集。(小型抽象固定集:线程、虚拟内存、I/O流)
Drawbridge ABI 通过两个组件实现:安全监视器 dkmon 和平台适配层 dkpal 。
dkmon 将 host OS 资源虚拟化到应用程序中,同时维护 library OS 和 host OS 之间的安全隔离边界。
dkmon 和 dkpal 等组件保证了 ABI 规范的严格兼容性。
dkmon 以 进程 的形式运行 Drawbridge 应用程序。
(可运行它的系统包括 Windows7 和 WindowsServer2008R2 、在 Windows7 上构建的 MinWin ,以及 Windows 下一版本的预发行版。还有此版本的 dkmon——在原始 Hyper-V VM 分区的 ring 0 中运行 Drawbridge 应用程序,同时依赖 Windows Server 2008 R2 主机提供 I/O流。所有这些平台上,Drawbridge library OS 的应用程序运行情况一致。)Drawbridge 进程通过调用 dkpal 访问 ABI 。
(三种 dkpal 实现:①不需要更改 host OS 内核,使用四个 host OS 调用通过匿名命名管道向dkmon发出请求;②它使用为 Xax 开发的技术在每个进程的基础上替换 NT系统 调用服务表[11];③是 Hyper-V 超级调用。)
- 需要注意 与应用程序关联的 manifest 文件。可在这些 manifest 文件中编码策略;manifest 白名单中列出了应用程序可以访问的 host OS 资源,这些资源是由 URI 路径标识的;manifest 还可以存储每个应用程序配置设置,这是个很方便的存储位置。
Drawbridge 进程通过调用 dkpal 访问 ABI 。我们有三种 dkpal 实现:
第一种,不需要更改 host OS 内核,使用四个 host OS 调用通过匿名命名管道向dkmon发出请求;
第二个,它使用为 Xax 开发的技术在每个进程的基础上替换 NT系统 调用服务表[11];
第三个是 Hyper-V 超级调用。
dkmon 使用标准 Windows 跨进程操作 API(ReadProcessMemory、VirtualAllocEx、VirtualFreeEx和DuplicateHandle)修改调用进程的地址空间和 host OS 句柄表,从而为 ABI 请求提供服务。作为一种优化,dkpal 通过直接调用兼容的 host OS 调用来实现一些简单的 ABI 调用(例如,阻塞等待、线程产量);这是安全的,因为 Drawbridge 进程无法创建 host OS 句柄。dkpal 当前调用 15个 不同的 host OS 调用。最终,我们希望将数据路径 dkmon 移动到主机内核中,以避免为某些 ABI 调用提供服务而进行完整地址空间更改的成本,并强化 Drawbridge 进程的边界;这将需要更新 dkpal ,但 Drawbridge library OS 中没有任何更改。
dkmon 使用主机 NT线程 和同步对象信号量、通知事件和同步事件来实现通过 ABI 公开的调度对象。因此,Drawbridge 线程驻留在主机内核的调度队列中,避免了不必要的调度开销。
library OS 使用 I/O流 实现文件、套接字和管道等高级抽象。安全监视器根据清单策略按 URI 过滤对 I/O流 的访问;在允许访问的地方,它将 I/O 定向到映射的资源。此间接寻址支持应用程序虚拟环境的运行时配置,并防止应用程序无意或恶意访问主机系统文件命名空间中的受保护资源。除非重写,否则监视器的默认策略仅允许 Drawbridge 进程访问与其应用程序映像位于同一主机目录中的文件。
例如,我们的 library OS 利用 I/O流 模拟 NT 文件对象和命名管道对象,以及网络套接字的代理接口。在后一种情况下,library OS 包括使用 tcp: 和 udp: URI 标识的 I/O流 的 ws2_32 的最低版本。安全监视器使用主机系统的 ws2_32 提供的套接字支持这些流;Drawbridge 通过提供 IP 数据包流接口并将 TCP 和 UDP 的实现移动到 library OS 中,可以提供更好的隔离。
举个例子:我们在应用程序上看到的文件系统并不是真正的文件系统,而是由 安全监视器 从 host OS 里的文件系统中虚拟出来的。
ps:想看更详细的 ABI 描述,请参见下面 第五个脚印:关门,放代码!
这样介绍还是太笼统了,能不能再详细一点?可以!
第四个脚印:开始具体重构吧!
重点(作者经验总结): 操作系统内核和主要操作系统子系统中的大部分代码与 Library OS 的上下文无关。【解释:很多 OS 允许多个应用程序和用户之间共享物理资源或虚拟资源,因此需要确保其系统安全性和一致性,但 Library OS 不允许这种资源共享,所以可以不需要考虑此类问题,这就省去了大部分代码。】
时刻记得这句:最大限度地提高应用程序的兼容性,同时最大限度地减少 Library OS 之外的依赖性。在这个思考基础上重构 Windows 7 ,作者给出了四步高级启发式方法:
-
确定一组具有代表性的应用程序所需的 API DLL 。(第一节就说过,只提取必要的API可以大大降低开销)
1)对应用程序二进制文件进行静态分析,以大致估计所需的 API DLL 集。
2)通过监视测试运行期间发出的 DLL 加载操作,使用动态检测工具对该集进行确定。
【具体地:在没有静态 stub 的情况下,DLL 加载时会调用 LoadLibrary (相当于Unix上的dlopen) ,同时它会生成一个动态的字符串。更保守一点,可以仅延迟限制特定 OS版本 加载的 DLL 。】 -
虚拟化 host OS 资源。(上一节提到: 安全监视器 通过其 Library OS 的 ABI 虚拟化一套 host OS 资源。)
没错,根据独立于 host OS 版本的高级 ABI ,安全监视器对 host(主机) 资源虚拟化。虚拟到哪里呢?作者在 Library OS 的底部实现了一个 NT内核仿真层(我估计这个仿真层就是上一节提到的 平台适配层 ),这个实现有两个优势:
1)这个仿真层相当薄。因为 host OS 通过 安全监视器 就提供了内核的许多复杂部分,如线程、虚拟内存、文件系统和网络等等。
2)Library OS 的其他部分更简单。因为它不需要多用户多路复用,所以 Drawbridge 注册表实现的代码行数是 Windows7 等效版本的 1/50 。虽然这个仿真层提供了 NT内核 的大部分接口,但其实这个仿真层存在一定“漏洞”,它会发生许多调用返回失败的情况。(包括访问或修改其他进程的所有请求,以及几乎所有 ioctl请求)。
作者认为这并不影响实验的进行,他们发现大多数应用程序要么就直接不使用未实现的接口,要么就在(使用较少的) API 返回失败结果时做出优雅的响应。【我对这句“优雅的响应”的理解是:忽略失败。但其实我认为这仍是问题,就算他们真的不影响,这也说明有一些接口在仿真层中是没必要存在的。】 -
解决依赖关系。
根据经验,我们在运行单个应用程序时,同时运行了大量的与服务相关的代码,但服务守护进程与 Windows子系统有依赖关系,我们要想让每个应用程序都能有其自身的 Library OS 副本(也就是使应用程序独立发展),就必须要解决这个依赖问题。两个办法:
1)要么 将代码移动到 Library OS 里面去;
2)要么就修改 API DLL ,删除其中的依赖关系。作者选择的是第一种方式。这是因为,这些服务守护进程是必要的,在保证多应用程序多用户的安全性或一致性需求的情况下,它们会替换部分代码以优化程序。
【具体地(我理解的):
win32k 和 rpcss 不能动,因为这些服务为应用程序提供了核心功能,所以要整体移到 Library OS 里面去;
相对的,csrss 、smss 和 wininit 主要帮助跨应用程序共享状态,所以(可以选第2种方式删依赖?),作者编写了定制的 Library OS 代码来替换它们
(关于 win32k 、csrss 、smss 、wininit 、rpcss ,忘了去看上面 第二个脚印 !!)】 -
模拟设备驱动程序。(这是把 library OS 当成主 OS 的意思吗?)
好,现在还需要一个模拟 Windows 子系统所需的设备驱动程序,这需要解决控制台和人机界面设备的依赖项。
1)键盘和鼠标驱动程序:使用能够提供简单输入队列的 stub 驱动程序来模拟。
2)显示驱动程序:使用能够绘制进程内帧缓冲区的 stub 驱动程序来模拟。
3) I/O 传输:(来自模拟设备的) I/O 通过无状态的 RDP连接 传输到桌面和用户。
4)RDP :通过重用来自 Windows7 内核模式 RDP服务器 的代码来实现该架构的 RDP 。【注意,这里不重用 RDP设备驱动程序 ,因为这些驱动程序可以被更简单的 stub 替代。】
Windows Library OS
将 Windows7 重构成一个 Library OS 是实现 Drawbridge 的最大部分工作。主要挑战包括:在对现有组件进行最小更改的情况下协调流程引导,在 Drawbridge ABI 上以用户模式模拟主机内核接口,移植系统范围的应用程序服务以在流程中运行,以及启用流程序列化和反序列化。我们相信,这些挑战将是将任何复杂的现代操作系统转换为桌面应用程序库操作系统所需的典型重构工作,我们的解决方案将应用于其他领域。然而,我们也认识到,我们的任务大大简化了,因为大多数Windows应用程序很少使用子进程,而且Windows API没有fork原语。
第五个脚印:关门,放代码!
ABI描述
ABI包括三个调用,用于分配、释放和修改基于页面的虚拟内存上的权限位。权限包括读、写、执行和保护。内存区域可以是未分配的、保留的或由提交的内存支持的:
VOID *DkVirtualMemoryAlloc(Addr, Size, AllocType, Prot);
DkVirtualMemoryFree(Addr, Size, FreeType);
DkVirtualMemoryProtect(Addr, Size, Prot);
ABI通过五个调用来创建、睡眠、生成调度程序量、恢复执行和终止线程,以及七个调用来创建、发送信号和阻塞同步对象,从而支持多线程:
DKHANDLE DkThreadCreate(Addr, Param, Flags);
DkThreadDelayExecution(Duration);
DkThreadYieldExecution();
DkThreadResume(ThreadHandle);
DkThreadExit(); DKHANDLE DkSemaphoreCreate(InitialCount, MaxCount); DKHANDLE DkNotificationEventCreate(InitialState); DKHANDLE DkSynchronizationEventCreate(InitialState);
DkSemaphoreRelease(SemaphoreHandle, ReleaseCount); BOOL DkEventSet(EventHandle);
DkEventClear(EventHandle); ULONG DkObjectsWaitAny(Count, HandleArray, Timeout);
Drawbridge中的主要I/O机制是I/O流。I/O流是可以被内存映射或顺序访问的字节流。流由URI命名。流ABI包括九个打开、读取、写入、映射、取消映射、截断、刷新、删除和等待I/O流的调用,以及三个访问I/O流元数据的调用。ABI故意不提供ioctl调用。支持的URI方案包括file:, pipe:,
http:, https:, tcp:, udp:, pipe.srv:, http.srv, tcp.srv:, 以及 udp.srv:.。后四种方案用于为服务器应用程序打开入站I/O流:
DKHANDLE DkStreamOpen(URI, AccessMode, ShareFlags, CreateFlags, Options);
ULONG DkStreamRead(StreamHandle, Offset, Size, Buffer);
ULONG DkStreamWrite(StreamHandle, Offset, Size, Buffer);
DkStreamMap(StreamHandle, Addr, ProtFlags, Offset, Size);
DkStreamUnmap(Addr);
DkStreamSetLength(StreamHandle, Length);
DkStreamFlush(StreamHandle);
DkStreamDelete(StreamHandle);
DkStreamWaitForClient(StreamHandle);
DkStreamGetName(StreamHandle, Flags, Buffer, Size);
DkStreamAttributesQuery(URI, DK_STREAM_ATTRIBUTES *Attr);
DkStreamAttributesQueryByHandle(StreamHandle, DK_STREAM_ATTRIBUTES *Attr);
ABI包括一个用于创建子进程的调用和一个用于终止正在运行的进程的调用。子进程不会从父进程继承任何对象或内存,父进程也不能修改其子进程的执行。父级可以使用其句柄等待子级退出。父级和子级可以在创建时通过父级提供给子级的I/O流进行通信:
DKHANDLE DkProcessCreate(URI, Args, DKHANDLE *FirstThread);
DkProcessExit(ExitCode);
最后,ABI包括七个不同的调用,用于获取挂钟时间、生成加密强随机位、刷新指令缓存部分、增加和减少线程之间共享对象的引用计数,以及在进程序列化期间协调线程与安全监视器:
LONG64 DkSystemTimeQuery();
DkRandomBitsRead(Buffer, Size);
DkInstructionCacheFlush(Addr, Size);
DkObjectReference(Handle);
DkObjectClose(Handle);
DkObjectsCheckpoint();
DkObjectsReload();
我们相信, Drawbridge ABI 的简洁性使得编码时间和运行时审查其隔离边界变得容易处理。我们在安全监视器中最大的 ABI 实现是 17KLoC 。
我们认识到 Drawbridge ABI 可以更小。虽然大小很重要,但在少数情况下,我们选择公开比严格必要的略大一点的抽象集,以便于将 Windows代码 移植到 library OS 中。我们的经验是,稍大一点的 ABI(比如说,再调用十几个)使移植现有代码变得更容易,并且使移植的代码更容易维护。例如,我们可以只公开一个同步原语,而不是公开信号量、通知事件和同步事件。事实上,ABI 的初始版本只有 19个 调用,同步对象和 I/O流 被合并成一个单一的管道抽象;例如,在 library OS 中,锁释放是作为管道上的单字节发送实现的,而获取是作为单字节写入实现的。ABI 更小,但关于 library OS 实现的推理更为痛苦。稍大的 ABI 允许安全监视器使用 host OS 可以更有效地支持的资源来实现虚拟化资源。
第六个脚印:万众期盼的 Drawbridge 测评
(弃了)
这篇关于【论文笔记】想自己重构操作系统吗?学学 Drawbridge 吧 —— 沙箱机制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!