技术应用
Linux的管道机制及其访问控制技术的改进
2016-01-09 09:12  

  方式之一。

  1.1无名管道(pipe)创建一个无名管道用系统调用intpipentfd),该系统调用的返回值或为1或为0,表示是否成功地创建了管道。在Linux系统中,每个文件都用一个在虚拟文件系统中称为i节点(inode)的数据结构来描述,每个i节点的文件描述信息包括。文件类型,拥有者,数据块指针等,无名管道也利用了i节点来描述相关信息。无名管道的实现包括两个指向同一个虚拟文件系统i节点的file结构,这个i节点又指向内存中的一个物理页面。管道结构如所示。图中有两个file数据结构,但它们定义的文件操作例程地址是不同的,其中一个指向向管道中写入数据的例程地址,另一个指向从管道中读出数据的例程地址。这样,虽然用户程序仍然使用通常的文件操作,而内核却利用这种抽象机制实现了对管道的特殊操作。当写进程在写管道时,数据被复制到共享的数据页面中:而当读进程读管道时,数据又从共享数据页中复制出来。Linux必须同步对管道的访问,使读进程和写进程步调一致。为了实现同步,Linux使用锁,等待队列和信号量这三种方式。

  图i管道结构示意图进程使用标准的写库函数write()来向管道中写入数据,系统根据库函数传递的文件描述符,可找到该管道的file结构,而该file结构中指定了用来进行写操作的函数地址,于是,内核调用该函数也就是/linux/fs/pipe.c中的函数pipewrite()来实现对管道的真正写操作。

  如果有足够大的空间把所有的数据写入管道中,并且该管道没有被读进程锁住,那么Linux就为写进程锁定管道,并把所有的待写字节复制到共享数据页中。如果管道被读进程锁定或者没有足够大的空间存放数据,那么当前进程被强制进入睡眠状态,放在管道的i节点的等待队列中,然后调用调度进程运行另一个进程。睡眠的进程是可中断的,它既可以接受信号,也可以在管道中有足够大空间来容纳写数据或在管道被解锁时,被读进程唤醒。写数据完成后,管道被解锁,系统会唤醒所有睡眠在i节点等待队列中的读进程。

  从无名管道中读数据的过程与向无名管道中写数据非常相似。但是进程可以在管道中没有数据或内存被锁定时立即返回错误信息,而不是阻塞该进程,这依赖于文件或管道的打开模式。反之,进程可以休眠在索引节点的等待队列中等待写进程写入数据。一旦所有的进程都完成了管道操作,管道的索引节点和其共享数据页会立即被释放。

  从上面的论述中,我们可看出Linux系统下的无名管道提供了一种功能很强的进程间的通信机构,但同时,无名管道存在如下两个严重的缺点:**,无名管道只能用于连接有共同祖先(有亲缘关系)的进程。由于无名管道是在程序中建立的,系统伴随无名管道的生成而分配随机的读/写文件描述符,程序的每一次运行其读/写文件描述符均不相同,只有靠父子进程间的继承关系才能传递管道文件描述符,这样就导致只有有亲缘关系的进程间才能使用同一无名管道。这一缺点是程序员在开发全系统范围内的服务程序时所不能忍受的。

  第二,无名管道。是依附进程而临时存在的。当利用管道通信的进程终止时,无名管道也随之消亡,它不是永久存在于系统中的。

  为了弥补无名管道的不足,UNIX系统又推出了一种无名管道的变种有名管道(FIFO),有名管道除了继承了无名管道的所有优点之外,还摒弃了无名管道的两个缺点。

  1.2命名管道Linux也支持有名管道(namedpipes)。因为这种管道遵循先进先出的原则,所以它也被称为FIFO(先进先出)管道。无名管道是临时性的对象,而FIFO管道是通过mkfifo或mknod命令创建的文件系统中的实体。只要知道了某一有名管道的文件名并且具有适当的权限,那么进程间(不管有无亲缘关系)就可以自由地使用FIFO管道。FIFO的打开方式与无名管道有所不同:无名管道(包括两个文件数据结构:虚拟文件系统的i节点和共享数据页)在进程每次运行时都会创建一次,而FIFO是一直存在的,需要用户打开和关闭。FIFO和无名管道在系统内核层合用了大量的代码段,它的读写流程与无名管道的读写流程基本一致。值得注意的是,UNIX系统规定,为了资源利用的合理性,如果未有进程打开FIFO用于写之前,而有进程打开FIFO用于读的话,那样该读进程将被阻塞,直到有另一个进程打开该FIFO用于写,反之亦然。解决这一问题的*好方法是推出一个后台进程将该FIFO以读写双重的方式打开操作。

  2Linux管道机制现有的访问控制技术现有的Linux管道机制能够方便地实现进程间信息的共享。其中无名管道机制在shell中使用广泛,主要用来使一个进程的标准输出成为另一个进程的标准输入,实现输入输出的重定向,因为无名管道只能在有亲缘关系的进程间共享数据,相互通信的进程都具有相同的祖先,所以系统没有提供像文件系统那样的根据用户身份进行访问控制(当前Linux的自主访问控制)的机制,而只是在对无名管道的读写时作一些常规性的检。有名管道与此不同,系统在创建FIFO时就设定了访问权限,当进程需要以一定模式打开某一FIFO时,必须经过/linux/fs/namei.c中的函数permission()的对该用户进行权限确认后才可以访问,函数permission)其实就是既定自主访问控制安全策略的实施函数,因此只要创建FIFO的用户开放了对其他用户的权限,其他用户就可以通过该FIFO进行通信了。

  3强制访问控制在管道中的实现虽然现有的通信机制对访问过程有一定的控制,但也存在着很多不安全的因素,例如在一个安全部门的安全操作系统中,如果高级别的进程为了通信而创建了一个FIFO,并且开放了对任意用户的读写权,那么,某一低级别且知道该管道名的的恶意进程不仅可以从FIFO中获取不利于系统安全的信息,甚至可以向管道中写入不安全的应用程序,如写入特洛伊木马来获取系统信息,从而来获得Root权限以破环系统。

  因此,要想加强系统的安全性,就要对管道通信进行更加严格的强制访问控制(MAC)。MAC*早出现在Multics系统中,1983年被美国国防部的TESEC采用,是B级安全系统的主要评价标准之一。MAC的基本思想是:每个主体都有一定的安全属性,每个客体也都有一定的安全属性。主体对客体是否能执行特定的操作取决于两者安全属性之间的关系。通常所说的MAC主要是指TCSEC中的MAC,它用来描述美国军用计算机系统环境下的多级安全策略。在多级安全策略中,安全属性用二元组(安全级,类别集合)表示。安全级表示机密程度,类别集合表示部门或组织的集合。一般的MAC都要求主体对客体的访问满足BLP(BellandLaPadula)安全模型的两个基本特性:简单安全特性:仅当主体的安全级别大于或等于客体的安全级别时,主体对客体才有“读”访问权。

  *-特性:仅当主体的安全级别小于或等于客体的安全级别时,主体对客体才有“写”访问权。

  上述两个特性保证了信息的单向流动,即信息只能向高安全属性的方向流动。MAC就是信息的单向流动来防止信息的扩散,抵制特洛伊木马对系统的攻击。

  在Linux管道机制中加入强制访问控制,就是把进程看作主体,管道看作客体,实现主客体分级,这样,即使创建管道的进程开放了低等级进程对管道的访问权限,通过强制访问控制低等级的进程也不能访问该管道,从而实现进程间的安全通信。

  因此,实现管道通信的强制访问控制的前提是每个进程具有主体应有的安全属性,管道具有客体应有的安全属性。本系统的实现中,管道的安全属性由创建该管道的进程决定,因此在知道了创建管道的进程的安全属性后,该管道的安全属性也就知道了。现在假定各进程具有安全属性,我们首先看一下FIFO的强制访问控制的实现。笔者认为FIFO的强制访问控制的实现有两种方法:一种是在虚拟文件系统层的函数permission)中原有访问权限检之前加入用于安全属性检的MAC,另一种方法是在低层管道文件系统中对FIFO实行真正操作的函数(piperead()和pipewrite())中加入MAC,这两种方案的实现分别如中所示的方案一和方案二,Linux支持很多目前流行的文件系统,如Ext,Ext2,minix,fat,管道文件系统等,为了简化起见,我们在图中只列出了三种文件系统,VFS是物理文件系统与服务之间的的其他进程看来都是相同的,但实际上,它所有的操作都是通过下一级的文件系统完成的。

  MAC实现方案从中可以看出方案一不仅对FIFO实现了强制访问控制,而且还对系统中其他类型的文件,如EXT2等文件实现了强制访问控制,方案二仅仅针对FIFO实现了强制访问控制。当要求对系统中的所有客体进行强制访问控制时,使用**种方法比较好,因为该方案实现了对系统中所有文件的强制访问控制,这有利于节省程序代码和便于统一管理,但是如果这种强制访问控制的加入使得某些涉及某个文件系统的应用程序无法运行或运行效率较低,而该应用程序暂时没有机会对系统造成危险,这时候应该采用第二种方案来满足要求,所以第二种方案的实现方法在应用上更具有灵活性。

  对无名管道来说,它在文件系统中不占有文件名,所以在对无名管道操作之前不需要进行打开操作,因此系统在创建了无名管道后,可直接调用库函数read()和write()对管道进行读写操作,这些库函数*后分别转化为piperead()和pipewrite()函数对管道进行具体的读写操作,因此,我们只要在piperead()和pipewrite()中加入安全属性的检的MAC就可以实现对无名管道的强制访问控制,其实这种方法与改进FIFO访问控制的第二种方案是一样的,因此,在系统只需实现对管道的强制访问控制的情况下,采用改进FIFO访问控制的第二种方案,不仅实现了对FIFO的强制访问控制,还实现了对无名管道的强制访问控制。

  本文的工作基于Linux的2.2.16版本的核心,上述方法均在该版本的系统中实现了。4结束语本文介绍了Linux的两种管道的数据结构和实现原理,并以此为基础,介绍了在一个安全性要求较高,各进程具有严格安全等级的Linux系统中,通过实现管道的强制访问控制以提篼系统安全性的方法,其中对FIFO的强制访问控制提出了两种实现方法,并简要介绍了它们的优缺点。但是MAC的引入在提高系统安全性的同时,不可避免地对系统的性能和Linux上的很多应用程序有影响,因此提篼Linux的安全机制还有很多问题需要研究。

  • 相关资讯