从句柄的概念再看分层设计
几个层次问题,首先物理内存和虚拟内存,操作系统管理物理内存,而用户进程使用虚拟内存,操作系统呈现给用户进程的是连续的虚拟内存但是不一定连续的物理内存,物理内存随时在变化,但是对于用户进程来说其虚拟内存地址是不变的;其次是指针和句柄,操作系统为了向用户空间提供若干台虚拟机并且又要管理一些所有进程需要的系统服务,必然不能将内核数据结构呈现给进程,但是进程确实可以使用这种数据,因此句柄就出现了,句柄其实
几个层次问题,首先物理内存和虚拟内存,操作系统管理物理内存,而用户进程使用虚拟内存,操作系统呈现给用户进程的是连续的虚拟内存但是不一定连续的物理内存,物理内存随时在变化,但是对于用户进程来说其虚拟内存地址是不变的;其次是指针和句柄,操作系统为了向用户空间提供若干台虚拟机并且又要管理一些所有进程需要的系统服务,必然不能将内核数据结构呈现给进程,但是进程确实可以使用这种数据,因此句柄就出现了,句柄其实是指针的指针,虽然它不是真正意义上的指针,由于操作系统管理的数据结构易变,并且处于高特权级,所以操作系统不能将之开放给用户空间,用户空间只能通过句柄来调用系统服务,进入内核之后,内核会根据句柄找到真正的内核数据结构,很多实现中句柄就是内核中进程块中一个表的索引字段,因为虚拟机是基于进程的,比如linux的task_struct中的打开文件表,在windows中的做法更是深刻,一切都是对象,因此每个对象都有句柄,进程,线程本身,文件,设备,窗口,...都有句柄,其进程块中有一个句柄表,每一个元素代表一个对象。正是因为windows的一切皆对象特性,其可以操作远程进程,因为进程是一个对象,而对象有句柄,有了句柄就可以操作,win32API中很多接口都是基于句柄的对象操作接口,在linux中似乎只有文件体现为句柄,也只有文件是进程可以共享的,由于没有别的句柄,因此也就不能随意操作别的对象。
句柄隐藏了内核的管理细节,呈现给进程一个平滑的结构,实际上句柄指向的真正的结构的地址是可以变化的,正如一个指针不变的情况下,其指向的数据可以变化,句柄的作用有二:第一,隐藏不必要的操作,作为唯一接口由API只开放可用的安全操作;第二,类似物理内存和虚拟内存的关系,向用户空间提供一个稳定的结构操作把手,将抽象从操作系统提升到进程。在操作系统中,抽象是基于文件,设备的,但是到了进程就统一都成了句柄,体现了在句柄指向的数据结构上的多路复用,按照分层原则,上层可以在下层提供的一个地址格式上多路复用,按照抽象的原则,越往上抽象程度越高,正如TCP和UDP可以复用一个IP地址一样,多个进程的多个句柄可以指向同一个内核数据结构。
句柄是一个层次间通信的通道,每一个进程虚拟机都通过句柄来使用共享的操作系统内核服务,但是这只是一类服务,进程虚拟机并不是靠句柄来使用操作系统的一切服务的,还有一类服务和操作系统一样可以直接使用更底层的硬件机制,比如MMU。前面的一篇文章说过,操作系统给进程虚拟机抽象两类指令,一类是安全的指令,这类指令直接并且始终在cpu-内存之间运行,运行这类指令不需要经过操作系统层,还有一类指令不是仅仅在cpu运行,而是牵扯到了没有提供多道程序环境的IO外设,对于这些资源的访问,进程必须使用操作系统的服务而不能直接使用硬件机制了。对于MMU而言,其实也是一种和句柄类似的抽象,多cpu上同时运行的不同进程可以同时访问相同的虚拟地址(非共享内存),但是通过MMU转换后的物理地址却不同,这就是多路复用概念的引申。本质上讲,MMU和操作系统内核是属于同一层次的,只不过MMU是硬件固有的机制,而操作系统内核提供一些管理策略,对于句柄而言,不同进程可以使用相同的句柄,但是指向的实际内核数据结构却不一定相同,因为句柄和虚拟内存一样,只在进程内部有意义,句柄是进程中内核数据结构的索引,是为了用户进程访问内核数据结构而设计的,这种设计非常好,规定了用户访问内核数据结构只能在规则下进行,而规则就是以句柄而参数的API的实现,其实就是系统调用的实现。
开放的句柄越多,对操作系统设计的安全要求就越高,只要有句柄,在得到句柄表的情况下就很容易得到实际的数据,在windows上,系统漏洞很多由此而发,而linux上仅仅开放了打开文件这个句柄,类似的漏洞也就很少了。为什么?句柄其实就是指针的指针,只不过这里的指针的含义更加抽象了,不是一般意义上的指针
更多推荐
所有评论(0)