设置内核运行环境之隔离的应用程序
隔离的应用程序
本文节选自《寒江独钓》一书
对于许多只进行高级语言的用户模式的应用程序编程的读者而言,编写一个“程序”在大多数情况下等价于编写一个可执行的应用程序。在Windows下,这意 味着建造一个exe文件。一个exe文件被双击执行后,在Windows系统中,产生一个“进程”(Process)。虽然在高级语言中很多细节被忽略, 但是在单个进程内的编程具有以下的特点:
(1)可以自由使用通用寄存器,不用关心这些寄存器被其他进程修改。换句话说,不同进程(本质上是线程)看似各自拥有一套通用寄存器。
(2)原则上可以自由使用0~N范围内的内存空间。N的大小取决于操作系统的位数(32位或者64位)。在Windows上实际编程有一些限制,但这些细 节暂时忽略,不用关心这些内存空间被其他进程修改。如果读者编写一个程序,对一个变量取地址,然后把这个地址设法传递给其他进程,那么另一个进程看见的地 址中的内容是一样的吗?答案当然是否定的,每个进程的用户空间内存是隔离的。
(3)通过操作系统约定的方式与其他进程共享其他资源,比如网络。大多数操作系统要求进程在使用TCP协议时必须打开一个端口,以避免和其他进程冲突。
因为有了这些特点,所以在单个进程内编程变得非常容易。编程者只需要定义和使用本进程所需要的资源,并编写代码操作这些资源即可,不需要关心其他进程。
虽然CPU有一些特性支持进程的隔离,但是更重要的是操作系统应用这些特性给各个进程提供了资源隔离的种种措施。这使应用程序的编程变得简单了,而且也变得更安全。因为大部分独立的应用程序,都不希望被其他应用程序影响。这中间的问题值得读者思考:
既然一个进程的可执行代码,都加载在这个进程的内存空间范围内,那么那些需要调用操作系统的调用才能实现的功能(比如说读取硬盘。大家应该不记得自己曾经 读/写端口,或者做过DMA,去实现读取硬盘的操作,显然驱动程序已经提供了这些功能),所需要的代码,它们位于什么空间呢?也在这个进程的内存空间范围 内吗?
答案当然是肯定的。不大可能有隔离的空间去容纳操作系统内核的代码(包括驱动程序)。
既然如此,是不是一个应用程序中的代码,就可以直接访问到操作系统的内核代码了呢?当然,如果是这样的话,那么只要编写一个应用程序,就可以直接修改操作系统内核的代码了(既然知道它们在哪里,当然总是可以设法修改它们)。