您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 公司方案 > unix环境高级编程--第8章 进程控制 (下)
发信人:scircle(yuanyuan),信区:Security标题:unix环境高级编程--第8章进程控制(下)发信站:BBS水木清华站(MonMar2715:59:572000)图〓六个exec函数之间的区别每个系统对参数表和环境表的总长度都有一个限制。在图中,这种限制是ARG-MAX。在P系统中,此值至少是4096字节。当使用shell的文件名扩充功能产生一个文件名表时,可能会受到此值的限制。例如,此命令grep-POSIX迹茫模*常病絊OURCE〓在某些系统上可能产生下列形式的shell错:arg〓〓list〓〓too〓〓由于历史原因,系统V中此限制是5120字节。和在分发时此限制是20,480字节。作者所用的系统则允许多至一兆字节!(见程序的输出前面曾提及在执行exec后,进程ID没有改变。除此之外,执行新程序的进程还保持了原进程的下列特征:·进程ID和父进程·实际用户ID和实际组·添加组·进程组·对话期·控制终端·闹钟尚余留的时间·当前工作目录·根目录·文件方式创建屏蔽字·文件锁·进程信号帘为?·末决信号·资源限制·tms-utime,tms-stime,tms-cutime以及tms-ustime值对打开文件的处理与每个描述符的进程中每个在exec时关闭标志值有关。回忆图3以及3节中对PD-CLOEXEC的说明,打开描述符都有一个在exec时关闭标志。若此标志设置,则在执行exec时关闭该描述符,否则该描述符的打开除非特地用fcntl设置了该标志,否则系统的默认操作是在exec后仍保持这种描述符打开。明确要求在exec时关闭打开目录流。(回忆节中所述的opendir函数。)这通常是由opendir函数实现的,它调用fcntl函数为对应于打开目录流的描述符设置在exec时关闭标志。注意,在exec前后实际用户ID和实际组ID保持不变,而有效ID是否改变则取决于所执行程序的文件的设置用户ID位和设置组ID位是否设置。如果新程序的设置用户ID位已设置,则有效用户ID变成程序文件属主的ID,否则有效用户ID不变。对组ID的处理方式与此相同。在很多Unix实现中,这六个函数中只有一个execve是系统核的系统调用。另外五个只是库函数,它们最终都要调用系统调用。这六个函数之间的关系示于图中。在这种安排中,库函数execlp和execvp使用PATH环境变量查找第一个包含名为filename的可执行文件的路径名前缀。图〓六个exec函数之间的关系实际程序例示了exec函数。程序〓exec函数的实例在该程序中先调用execle,它要求一个路径名和一个特定的环境。下一个调用的是execlp,它用一个文件名,并将调用者的环境传送给新程序。execlp在这里能够工作的原因是因为目录/home/stevens/bin是当前路径前缀之一。注意,我们将第一个参数(在新程序中的argv[0])设置为路径名的文件名分量。某些shell将此参数设置为完全的路径名。在程序中要执行两次的程序echoall示于程序中。这是一个普通程序,它回送其所有命令行参数及其全部环境表。程序〓回送所有命令行参数和所有环境字符串执行程序时得到:$argv[0]argv[1]argv[2]:MYargv[0]$argv[1]:only131linesthataren't其中31行没有显示注意,shell提示出现在第二个exec打印argv[0]和argv[1]之间。这是因为父进程并不等待该子进程结束。〓更改用户ID和组可以用setuid函数设置实际用户ID和有效用户ID。与此类似,可以用setgid函数设置实际组ID和有效组ID。#include#includeintsetuid(uid迹茫模*常病絫intsetgid(gid迹茫模*常病絫Bothreturn:0ifOK,-1onerror两个函数返回:若成功为0,出错为-关于谁能更改ID有若干规则。现在先考虑有关改变用户ID的规则(在这里关于用户ID所说明的一切都适用于组ID)。若进程具有超级用户特权,则setuid函数将实际用户ID,有效用户ID,以前保存的设置用户ID设置为uid。若进程没有超级用户特权,但是uid等于实际用户ID或保存的设置用户ID,则setuid只将有效用户ID设置为uid。不改变实际用户ID和保存的设置用户ID。如果上面两个条件都不满足,则errno设置为EPERM,并出错返回。在这里假摇迹茫模*常病絇OSIX迹茫模*常病絊AVED迹茫模*常病絀DS为真。如果没有提供这种功能,则上面所说的关于保存的设置用户ID的部分都无效。FIPS151-1要求此功能。SVR4支持迹茫模*常病絇OSIX迹茫模*常病絊AVED迹茫模*常病絀DS功能。关于系统核所维护的三个用户ID,还要注意下列几点:只有超级用户进程可以更改实际用户ID。通常,实际用户ID是在用户登录时,由login(1)程序设置的,而且决不会改变它。因为login是一个超级用户进程,当它调用setuid时,设置所有三个用户ID。仅当对程序文件设置了设置-用户-ID位时,exec函数再设置有效用户ID。如果设置-用户-ID位没有设置,则exec函数不会改变有效用户ID,而将其维持为原先值。任何时候都可以调用setuid,将有效用户ID设置为或者实际用户ID,或者保存的设置-用户-ID。自然,不能将有效用户ID设置为任一随机值。保存的设置-用户-ID是由exec从有效用户ID复制的。在exec按文件用户ID设置了有效用户ID后,即进行这种复制,并将此副本保存起来。图摘要列出了改变这三个用户ID的不同方法。图〓改变三个用户ID的不同方法注意,用节中所述的getuid和geteuid函数只能获得实际用户ID和有效用户ID的当前值。我们不能获得所保存的设置-用户-ID的当前值。实例为了说明保存的设置-用户-ID特征的用法,让我们先观察一个使用该特征的程序。我们所观察的是贝克莱tip(1)程序(系统V的cu(1)程序与此类似。)这两个程序都连接到一个远程系统,或者是直接连接,或者是拨号一个调制解调器。当tip使用一个调制解调器时,它必须通过使用锁文件来独占使用它。此锁文件是与UUCP共享的,因为这两个程序可能在同时要使用同一调制解调器。将发生下列步骤:程序文件是由用户uucp拥有的,并且其设置-用户-ID位已设置。当exec此程序时,则关于用户ID得到下列结果:实际用户ID=我们的用户有效用户ID=保存设置用户ID=存取所要求的锁文件。这些锁文件是由名为UUCP的用户所拥有的,因为有效用户ID是UUCP,所以tip可以存取这些锁文件。执行setuid(getuid())。因为tip不是超级用户进程,所以这仅仅改变有效用户ID。此时得到:实际用户ID=我们的用户ID(未改变有效用户ID=我们的用户ID(未改变保存设置用户ID=UUCP(未改变现在,tip进程是以我们的用户ID作为其有效用户ID而运行的。这就意味着能存取的只是我们通常可以存取的,没有附加的存取权。当执行完我们所需的操作后,tip执行setuid(uucpuid),其中uucpuid是用户uucp的数值用户ID(tip很可能在起动时调用geteuid,得到uucp的用户ID,然后将其保存起来,我们并不认为tip会搜索口令字文件以得到这一数值用户ID。)因为setuid的参数等于保存的设置-用户-ID,所以这种调用是许可的(这就是为什么需要保存的设置-用户-ID的原因。)现在得到:实际用户ID=我们的用户ID(末改变有效用户保存设置用户ID=uucp(末改变现在可对其锁文件进行操作以释放它们,因为tip的有效用户ID是。以这种方法使用保存的设置-用户-ID,在进程的开始和结束部分就可以使用由于程序文件的设置用户ID而得到的额外的优先权。但是,进程在其运行的大部分时间只具有普通的许可权。如果进程不能在其结束部分切换回保存的设置-用户-ID,那么就不得不在全部运行时间都保持额外的许可权(这可能会造成麻烦)。让我们来看一看如果在tip运行时为我们生成一个shell进程(先fork,然后exec)将发生什么。因为实际用户ID和有效用户ID都是我们的普通用户ID(上面的第三步),所以该shell没有额外的许可权。它不能存取tip运行时设置成uucp的保存的设置-用户-ID,因为该shell的保存的设置-用户-ID是由exec复制有效用户ID而得到的。所以在执行exec的子进程中,所有三个用户ID都是我们的普通用户ID。如若程序是设置-用户-ID为root,那么我们关于tip如何使用setuid所作的说明是不正确的。因为以超级用户特权调用setuid就会设置所有三个用户ID。使上述实例按我们所说明的进行工作,只需setuid设置有效用户ID。setreuid和setregid函数支持函数,其功能是交换实际用户ID和有效用户ID的值。#include#includeintsetreuid(uid迹茫模*常病絫迹茫模*常病絫intsetregid(gid迹茫模*常病絫迹茫模*常病絫Bothreturn:0ifOK,-1onerror〓两个函数返回:若成功为0,出错为-其作用很简单:一个非特权用户总能交换实际用户ID和有效用户ID。这就允许一个设置-用户-ID程序转换成只具有用户的普通许可权,以后又可再次转换回设置-用户-ID所得到的额外许可权。引进了保存的设置-用户-ID特证后,其作用也相应加强,它也允许一个非特权用户将其有效用户ID设置为保存的设置-用户-ID。SVR4在其BSD兼容库中也提供这两个函数。并没有上面所说的保存的设置-用户-ID功能。它用setreuid和setregid来代替。这就允许一个非特权用户前、后交换这二个用户ID的值,而中的tip程序就是用这种功能编写的。但是要知道,当此版本生成shell进程时,它必须在exec之前,先将实际用户ID设置为普通用户ID。如果不这样做的话,那么实际用户ID就可能是uucp(由setreuid的交换操作造成。)然后shell进程可能会调用setreuid交换两个用户ID值并取得uucp许可权。作为一个保护性的程序设计措施,tip将子进程的实际用户ID和有效用户ID都设置成普通用户ID。seteuid和setegid函数在对POIX的建议更改中包含了两个函数seteuid和setegid。它们只更改有效用户ID和有效组ID。#include#includeintseteuid(uid迹茫模*常病絫intsetegid(gid迹茫模*常病絫Bothreturn:0ifOK,-1onerror〓两个函数返回:若成功为0,出错为-一个非特权用户可将其有效用户ID设置为其实际用户ID或其保存的设置-用户-ID。对于一个特权用户则可将有效用户ID设置为uid。(这区别于setuid函数,它更改三个用户ID。)这一建议更改也要求支持保存的设置-用户-ID。SVR4和都支持这两种函数。图〓摘要列出了本节所述的修改三个不同的用户ID的各个函数。图〓设置不同的用户ID的各函数摘要组至此,在本章中所说明的一切都以类似方式适用于各个组ID。添加组ID不受setgid函数的影响。〓解释器文件SVR4和都支持解释器文件。这种文件是文本文件,其起始行的形式是:#!pathname[optional-argument]在骛叹号和pathname之间的空格是可任选的。最常见的是以下列行开始:#!pathname通常是个绝对路径名,对它不进行什么特殊的处理(不使用PATH进行路径搜索)。对这种文件的识别是由系统核作为exec系统调用处理的一部分来完成的。系统核使调用exec函数的进程实际执行的文件并不是该解释器文件,而是在该解释器文件的第一行中pathname所指定的文件。一定要将解释器文件(文本文件,它以#!开头)和解释器(由该解释器文件第一行中的pathname指定)区分开来。要了解,很多系统对解释器文件第一行有长度限止(32个字符)。这包括#!,pathname,
本文标题:unix环境高级编程--第8章 进程控制 (下)
链接地址:https://www.777doc.com/doc-3398764 .html