Can We Make Operating Systems Reliable and Secure?
作者:Andrew S. Tanenbaum,Jorrit N. Herder,Herbert Bos
原文链接:ast-Computer06.pdf
1 问题与原因
1.1 问题
- 可靠性(reliability):如缓冲区溢出导致系统奔溃。
- 安全性(security):如利用缓冲区溢出运行病毒或蠕虫。
1.2 原因
- 工程浩大(huge):1000行可执行代码中会有6-16个bugs1,所以Linux内核中将可能有 15,000 个bugs。
- 错误孤岛(fault isolation):巨大的代码量导致没有人能真正理解整个项目,如同木桶理论,系统性能下降。
2 解决办法
2.1 武装内核(ARMORED OPERATING SYSTEMS)2
在宏内核结构的系统中,将容易出错(错误率是普通代码的3-7倍3)的驱动程序用wrapper包住,以监控其运行状态,提供轻量级的保护域(其中桩stub由驱动的exported和imported函数构成):
- 隔离性(Isolation):使用虚拟内存页表映射技术,不属于驱动的页表权限为只读。
- 干涉性(Interposition):驱动向内核提供需要调用到的函数指针组成的数组,内核向驱动提供系统调用。
- 恢复性(Recovery):驱动奔溃后,处于用户态的恢复代理程序会去查询配置数据库,以进行相关设置——通常情况下是重启驱动,此时系统可以恢复正常,但与该驱动相关的应用程序将无法运行,此时可以使用影子驱动使应用程序继续运行。
- 影子驱动(shadow drivers):正常运行时,影子驱动会记录驱动与内核的通信日志。当驱动需要重启时,可访问日志,恢复为原运行状态。
- 制约性(Limitations):Nooks模型只能捕捉到99%的致命驱动错误、55%的非致命驱动错误。
2.2 泛虚拟机(PARAVIRTUAL MACHINES)
运行一个叫“虚拟机监控”的控制程序,该程序运行在裸机而不是操作系统上,以创建真实机器的多个实例:
- By putting the device drivers in one or more virtual machines separated from the main one running the rest of the operating system and the application programs——将驱动分割到不同的虚拟机中。
- Physical I/O is handled by the addition of about 3000 lines of code to the Linux kernel on which the drivers run to allow them to use the L4 services for I/O instead of doing it themselves——将硬件I/O的控制从Linux内核移到L4微内核中。
- Another 5000 lines of code were added to handle communication between the three drivers ported (disk, network, and PCI bus) and the virtual machine running the application programs——添加硬盘、网络、PCI总线的通信。
- The overhead of using paravirtualized machines is about 3–8%——泛虚拟机花费的系统资源为3–8%。
2.3 多服务操作系统(MULTISERVER OPERATING SYSTEMS)
内核态只运行一个微内核,操作系统的其他部分将作为服务或驱动进程运行在独立的用户态中。
- 多服务架构(Multiserver Architecture)
- 进程间通信(Interprocess Communication):采用非阻塞的发送者、接收者模式
- 可靠性(Reliability Features):MINIX 3内核代码只有4000行,平均可能出现24个bugs;驱动运行在用户态,控制容易。
- 性能(Performance Considerations):
- 驱动移到用户态后,牺牲的系统性能 ≤10%
- 内核能够在几秒内重建
2.4 基于语言的保护(LANGUAGE-BASED PROTECTION)
不使用带有“指针“等其他问题的C/C++语言设计操作系统,而使用类型安全的编程语言。如Algol
,该语言的安全性不是通过MMU,而是通过Algol编译器的拒绝以避免产生危险的代码。
- 概述:由Sing#(加入”消息传递原语“的增强型C#语言)写成的系统Singularity,该系统的运行由语言的安全性进行约束,所有的进程都能运行在同一个虚拟地址空间中。
- 安全:编译器禁止进程访问其他进程的数据。
- 高效:没有内核陷阱(kernel traps)和上下文切换(context switches)。
- 微内核结构(The Microkernel):微内核进程和用户进程都运行在同一个虚拟地址空间中。
- 进程间通信(Interprocess Communication):用户进程通过点对点双向通道向微内核发送强类型消息,获取系统服务。
contract C1 {
//消息处理函数
in message Request(int x) requires x > 0;
out message Reply(int y);
out message Error();
//状态机
state Start:
Request? -> Pending;
state Pending: one {
Reply! -> Start;
Error! -> Stopped;
}
state Stopped: ;
}
- 堆(The Heap):每个进程的数据都是完全私有的,磁盘驱动将数据块放到堆后,通过零拷贝(zero copies)将使用权从磁盘转移到用户。
- 文件系统(The File System):使用单分层名字空间,服务都挂载在根目录下。
- 验证(Verification):使用元数据(metadata)记录系统模块的依赖、对外接口、资源、行为。
3 结论
- 文中讨论的四种方法都是防止易错的驱动对系统的破坏,提高系统可靠性:
- ARMORED OPERATING SYSTEMS和PARAVIRTUAL MACHINES是对现有系统的驱动进行运行隔离,以提高可靠性。
- MULTISERVER OPERATING SYSTEMS和LANGUAGE-BASED PROTECTION是重新设计系统内核,以实现驱动的运行隔离,提高系统可靠性。
【笔者按】:这篇文章是作者于2006年为Computer magazine写的封面文章。作者Tanenbaum教授与Linux之父Linus素有争执(Tanenbaum–Torvalds debate),关于系统内核应该采用宏内核还是微内核。文章结尾算是为这场争论定下注脚,作者一方面承认由于现在微内核结构性能不佳,现在操作系统普遍采用宏内核(或者混和内核);另一方面,作者觉得为了可靠性和安全性,未来微内核结构会在操作系统设计中卷土重来。
- V.R. Basili and B.T. Perricone, “Software Errors and Complexity: an Empirical Investigation,” Commun. of the ACM, vol. 27, Jan. 1984, pp. 42-52. ↩
- M. Swift, B. Bershad, and H. Levy, “Improving the Reliability of Commodity Operating Systems,” ACM Trans. on Operating Systems, vol. 23, pp. 77-110, 2005. ↩
- A. Chou, J. Yang, B. Chelf, S. Hallem, and D. Engler, “An Empirical Study of Operating System Errors,”Proc. 18th ACM Symp. on Operating Syst. Prin., ACM, pp. 73-88, 2001. ↩