Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1093245
  • 博文数量: 242
  • 博客积分: 10209
  • 博客等级: 上将
  • 技术积分: 3028
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-12 09:27
文章分类

全部博文(242)

文章存档

2014年(1)

2013年(1)

2010年(51)

2009年(65)

2008年(124)

我的朋友

分类: LINUX

2009-04-11 15:34:26

转载自

引用:Maurice J.Bach 的《The Design of The UNIX Operating System》一书中对这个问题的论述。。。



p227

7.6 THE USER ID OF A PROCESS

内核会给每个进程关联两个和进程ID无关的用户ID,一个是真实用户ID,还有一个是有效用户ID或者称为 setuid(set user ID)。真实用户ID用于标识由谁为正在运行的进程负责。有效用户ID用于为新创建的文件分配所有权、检查文件访问许 可,还用于通过kill系统调用向其它进程发送信号时的许可检查。内核允许一个进程以调用exec一个setuid程序或者显式执行setuid系统调用 的方式改变它的有效用户ID。

所谓setuid程序是指一个设置了许可模式字段中的setuid bit的可执行文件。当一个进程exec一个setuid程序的时候,内核会 把进程表以及u区中的有效用户ID设置成该文件所有者的ID。为了区分这两个字段,我们把进程表中的那个字段称作保存用户ID。可以通过一个例子来演示这 两个字段的区别。

setuid系统调用的语法是 setuid(uid) ,其中,uid是新的用户ID,该系统调用的结果取决于有效用户ID的当前值。如果调用 进程的有效用户ID是超级用户,内核会把进程表以及u区中的真实和有效用户ID都设置成uid。如果调用进程的有效用户ID不是超级用户,仅当uid等于 真实用户ID或保存用户ID时,内核才会把u区中的有效用户ID设置成uid。否则,该系统调用将返回错误。一般来说,一个进程会在fork系统调用期间 从父进程那儿继承它的真实和有效用户ID,这些数值即使经过exec系统调用也会保持不变。

存储在u区中的有效用户ID是最近一次setuid系统调用或是exec一个setuid程序的结果;只有它会被用于文件访问许可。进程表中的保存用户ID使得一个进程可以通过执行setuid系统调用把有效用户ID设置成它的值,以此来恢复最初的有效用户ID。

setuid程序的例子:login,mkdir。




引用:Uresh Vahalia 的《UNIX Internals:The New Frontiers》一书中对这个问题的论述。。。 

p27

2.3.3 User Credentials

UID和GID这样的标识符会影响文件的所有权和访问许可,以及向其它进程发送信号的能力。这些属性统称为凭证。

每个进程都有两对ID ——真实的和有效的。当一个用户登录的时候,login程序会把两对ID设置成密码数据库(/etc/passwd文件, 或某些如Sun Microsystems的NIS之类的分布式机制)中指定的UID和GID。当一个进程fork的时候,子进程将从父进程那儿继承它的 凭证。

有效UID和有效GID印象文件的创建和访问。在创建文件的时候,内核将文件的所有者属性设置成创建进程的有效UID和有效GID。在访问文件的 时候,内核使用进程的有效UID和GID来判断它是否能够访问该文件。真实UID和真实GID标识进程的真实所有者,会影响到发送信号的权限。对于一个没 有超级用户权限的进程来说,仅当它的真实或有效UID于另一个进程的真实UID匹配时它才能向那个进程发送信号。

有三个系统调用可以改变凭证。如果一个进程调用exec执行一个安装为suid模式的程序,内核将把进程的有效UID修改成文件的所有者。同样, 如果该程序安装为sgid模式,内核则会去修改调用进程的有效GID。UNIX提供这个特性是想赋予用户特殊的权限以完成一些特定的任务。

一个用户还可以通过调用setuid或setgid来改变它的凭证。超级用户可以通过这些系统调用改变真实的和有效的UID以及GID。普通用户则只能通过这些调用来把它们的有效UID或GID改回到真实的数值。

System V和BSD UNIX在处理凭证方面存在着一些差别。SVR3还维护了一个saved UID和saved GID,分别是在调用 exec之前的有效UID和GID的数值。setuid和setgid系统调用还可以把有效ID恢复为保存的数值。4.3BSD不支持这一特性,它允许一 个用户属于一个辅组(supplemental group)的集合(使用setgroups系统调用)。用户创建的文件将属于它的主组 (primary group),而用户则既可以访问属于主组的文件,也可以访问属于辅组的文件。

SVR4整合了上述所有特性。它支持附组,也会在exec的时候维护saved UID和GID。

setuid程序的例子:passwd。




引用:Marshall Kirk McKusick, George V. Neville-Neil 的《The Design and Implementation of the FreeBSD Operating System》一书中对这个问题的论述。。。 

3.7 User, Group, and Other Identifiers

每个FreeBSD进程的状态里都有一个UID和一组GID。一个进程的文件系统访问特权就是由它的UID和GIDs来定义的。通常,这些标识符 都是新进程创建的时候从父进程那儿自动继承过来的。只有超级用户才能修改一个进程的真实UID或真实GID。这个方案在各种特权之间进行了严格的区分,确 保除了超级用户之外的其它任何用户都无法获得特权。

每个文件都有三组许可bit,分别用于所有者、组以及其它用户的读、写或执行许可。这些许可bit将按如下顺序进行检查:
    1、如果文件的UID和进程的UID相同,则仅应用所有者的许可,不再检查组和其它用户的许可。
    2、如果UID不匹配,但文件的GID和进程的众多GID之一匹配,则仅引用组的许可,不再检查所有者和其它用户的许可。
    3、仅当进程UID和GID与文件的UID和GID都不匹配时,才会去检查其它用户的许可。如果这些许可不允许所请求的操作,该操作就会失败。

一个进程的UID和GIDs是从它的父进程那儿继承来的。当一个用户登录的时候,login程序会在执行exec系统调用运行用户的登录shell之前设置好UID和GIDs,因此,后续的所有进程都会继承到恰当的标识符。

我们经常会想赋予一个用户有限的额外特权。......为了解决这个问题,内核允许程序在运行过程中创建被赋予特权的程序。以不同的UID运行的 程序被称为setuid程序,以一个额外的组特权运行的程序被称为setgid程序。当运行一个setuid程序的时候,进程的许可将被扩展以包括与程序 相关联的UID的许可。该程序的UID就被称为进程的有效UID,而进程最初的UID则被称为真实UID。同样,执行一个setgid程序会把进程的许可 扩展为程序的GID的许可,相应的也有有效GID和真实GID的定义。

系统可以通过setuid和setgid程序来提供对文件或服务的受控访问。当然,这样的程序必须仔细编写,以保证它们只具有一些有限的功能。

UID和GIDs是作为每个进程的状态的一部分来维护的。由于历史原因,GIDs被实现成了一个显著的GID(即有效GID)和一个GIDs的辅 助数组,不过在逻辑上则被看作是一组GIDs。在FreeBSD中,那个显著的GID就是GIDs数组中的第一个条目。辅助数组的大小是固定的 (FreeBSD中是16),不过可以通过重新编译内核来修改这个数值。

FreeBSD是通过把运行setgid程序的进程的辅组数组中的第0个元素设置成文件的属组来实现setgid功能的。之后就可以像普通进程那 样对许可进行检查了。由于存在额外的组,setgid程序就能够比一个运行没有特殊权限的程序的用户进程访问更多的文件。为了避免在运行一个setgid 程序的时候丢失与第0个数组元素中的组相关联的特权,login程序会在初始化用户的辅组数组的时候将第0个数组元素复制到第一个数组元素中。因此,当运 行的setgid程序修改第0个元素的时候,用户不会丢失任何特权,因为曾经保存在第0个数组元素中的组仍然可以从第一个数组元素中得到。

setuid功能是通过把进程的有效UID从用户的数值修改为被运行的程序的数值来实现的。和setgid一样,保护机制此时将毫不变样地允许访 问,同时也不会意识到程序正在运行setuid。由于一个进程在同一时刻只能有一个UID,在运行setuid的时候就可能会丢失某些特权。在加载新的有 效UID的时候,之前的真实UID将会继续作为真实UID。不过真实UID是不会用于任何确认检查的。

一个setuid进程在运行过程中可能会想临时取消它的特殊权限。比如,它可能只在运行开始和结束的时候需要访问某个受限文件的特殊权限。在其余 的运行时间中,它应当只具有真实用户的权限。在BSD的早期版本中,特权的回收是通过对真实的和有效的UID进行切换来完成的。由于只有有效UID被用于 访问控制,这个方法既提供了所需的语义,又提供了一个隐藏特殊权限的地方。这个方法的缺点是很容易就混淆了真实的和有效的UID。

在FreeBSD中,使用了一个额外的标识符,即saved UID来记录setuid程序的身份。当一个程序被exec之后,它的有效UID会 被拷贝到saved UID中。下表中的第1行表示了一个没有特权的程序,它的真实、有效以及saved UID都是真实用户的数值。第2行正在运行中的 setuid程序,它的有效UID被设置成了具有相应特权的UID,而这个特权UID也会被拷贝到saved UID中。

Actions affecting the real, effective, and saved UIDs.
_________________________________________________________________
Action            Real    Effective    Saved

1.exec-normal     R       R            R
2.exec-setuid     R       S            S
3.seteuid(R)      R       R            S
4.seteuid(S)      R       S            S
5.seteuid(R)      R       R            S
6.exec-normal     R       R            R

Key:R-real user identifier; S-special-privilege user identifier
_________________________________________________________________


seteuid系统调用只会修改有效UID,而不会影响真实的或saved UID。seteuid系统调用被允许将有效UID修改为真实的或 saved UID的数值。表中的第3行和第4行表示了一个setuid程序在一直保持正确的真实UID的同时是如何放弃和重新取回它的特殊权限的。第5 行和第6行表示了一个setuid程序可以运行一个子进程而不赋予它特殊权限。首先,它会把它的有效UID设置成真实UID。然后,当exec那个子进程 的时候,有效UID就会被拷贝到saved UID中,从此就会失去对特权UID的所有访问。

与此类似,也有一个saved GID机制,允许进程在真实GID和最初的有效GID之间进行切换。




引用:IEEE Std 1003.1™, 2004 Edition

Standard for Information Technology —
Portable Operating System Interface (POSIX)

System Interfaces   中对setuid()的论述。。。


NAME

    setuid—set user ID

SYNOPSIS

    #include 

    int setuid(uid_t uid);

DESCRIPTION

    If the process has appropriate privileges, setuid( ) shall set the real user ID, 
    effective user ID, and the saved set-user-ID of the calling process to uid.

    If the process does not have appropriate privileges, but uid is equal to the real user
    ID or the saved set-user-ID, setuid( ) shall set the effective user ID to uid; the real
    user ID and saved set-user-ID shall remain unchanged.

    The setuid( ) function shall not affect the supplementary group list in any way.

RETURN VALUE

    Upon successful completion, 0 shall be returned. Otherwise, ?1 shall be returned and
    errno set to indicate the error.

ERRORS

    The setuid( ) function shall fail, return ?1, and set errno to the corresponding value
    if one or more of the following are true:

    [EINVAL]    The value of the uid argument is invalid and not supported by the
                implementation.

    [EPERM]     The process does not have appropriate privileges and uid does not match the
                real user ID or the saved set-user-ID.

EXAMPLES

    None.

APPLICATION USAGE

    None.

RATIONALE

    The various behaviors of the setuid( ) and setgid( ) functions when called by 
    non-privileged processes reflect the behavior of different historical implementations. 
    For portability, it is recommended that new non-privileged applications use the 
    seteuid( ) and setegid( ) functions instead.

    The saved set-user-ID capability allows a program to regain the effective user ID 
    established at the last exec call. Similarly, the saved set-group-ID capability allows 
    a program to regain the effective group ID established at the last exec call. 
    These capabilities are derived from System V. Without them, a program might have to run
    as superuser in order to perform the same functions, because superuser can write on the
    user’s files. This is a problem because such a program can write on any user’s files,
    and so must be carefully written to emulate the permissions of the calling process 
    properly. In System V, these capabilities have traditionally been implemented only via
    the setuid( ) and setgid( ) functions for non-privileged processes. The fact that the 
    behavior of those functions was different for privileged processes made them difficult 
    to use. The POSIX.1-1990 standard defined the setuid( ) function to behave differently
    for privileged and unprivileged users. When the caller had the appropriate privilege, 
    the function set the calling process’ real user ID, effective user ID, and saved 
    set-user ID on implementations that supported it. When the caller did not have the 
    appropriate privilege, the function set only the effective user ID, subject to 
    permission checks. The former use is generally needed for utilities like login and su, 
    which are not conforming applications and thus outside the scope of IEEE Std 
    1003.1-2001. These utilities wish to change the user ID irrevocably to a new value, 
    generally that of an unprivileged user. The latter use is needed for conforming 
    applications that are installed with the set-user-ID bit and need to perform operations
    using the real user ID.

    IEEE Std 1003.1-2001 augments the latter functionality with a mandatory feature named
    _POSIX_SAVED_IDS. This feature permits a set-user-ID application to switch its 
    effective user ID back and forth between the values of its exec-time real user ID and 
    effective user ID. Unfortunately, the POSIX.1-1990 standard did not permit a conforming 
    application using this feature to work properly when it happened to be executed with 
    the (implementation-defined) appropriate privilege. Furthermore, the application did 
    not even have a means to tell whether it had this privilege. Since the saved 
    set-user-ID feature is quite desirable for applications, as evidenced by the fact that 
    NIST required it in FIPS 151-2, it has been mandated by IEEE Std 1003.1-2001. However, 
    there are implementors who have been reluctant to support it given the limitation 
    described above.

    The 4.3BSD system handles the problem by supporting separate functions: setuid( ) 
    (which always sets both the real and effective user IDs, like setuid( ) in IEEE Std 
    1003.1-2001 for privileged users), and seteuid( ) (which always sets just the effective
    user ID, like setuid( ) in IEEE Std 1003.1-2001 for non-privileged users). This 
    separation of functionality into distinct functions seems desirable. 4.3BSD does not 
    support the saved set-user-ID feature. It supports similar functionality of switching 
    the effective user ID back and forth via setreuid( ), which permits reversing the real 
    and effective user IDs. This model seems less desirable than the saved set-user-ID 
    because the real user ID changes as a side effect. The current 4.4BSD includes saved
    effective IDs and uses them for seteuid( ) and setegid( ) as described above. The 
    setreuid( ) and setregid( ) functions will be deprecated or removed.

    The solution here is:

      . Require that all implementations support the functionality of the saved 
        set-user-ID, which is set by the exec functions and by privileged calls to 
        setuid( ).

      . Add the seteuid( ) and setegid( ) functions as portable alternatives to setuid( ) 
        and setgid( ) for non-privileged and privileged processes.

    Historical systems have provided two mechanisms for a set-user-ID process to change its
    effective user ID to be the same as its real user ID in such a way that it could return
    to the original effective user ID: the use of the setuid( ) function in the presence of
    a saved set-user-ID, or the use of the BSD setreuid( ) function, which was able to swap
    the real and effective user IDs. The changes included in IEEE Std 1003.1-2001 provide a
    new mechanism using seteuid( ) in conjunction with a saved set-user-ID. Thus, all 
    implementations with the new seteuid( ) mechanism will have a saved set-user-ID for 
    each process, and most of the behavior controlled by _POSIX_SAVED_IDS has been changed 
    to agree with the case where the option was defined. The kill ( ) function is an 
    exception. Implementors of the new seteuid( ) mechanism will generally be required to 
    maintain compatibility with the older mechanisms previously supported by their systems. 

    However, compatibility with this use of setreuid( ) and with the _POSIX_SAVED_IDS
    behavior of kill ( ) is unfortunately complicated. If an implementation with a saved 
    set-user-ID allows a process to use setreuid( ) to swap its real and effective user 
    IDs, but were to leave the saved set-user-ID unmodified, the process would then have an
    effective user ID equal to the original real user ID, and both real and saved 
    set-user-ID would be equal to the original effective user ID. In that state, the real 
    user would be unable to kill the process, even though the effective user ID of the 
    process matches that of the real user, if the kill ( ) behavior of _POSIX_SAVED_IDS
    was used. This is obviously not acceptable. The alternative choice, which is used in 
    at least one implementation, is to change the saved set-user-ID to the effective user 
    ID during most calls to setreuid( ). The standard developers considered that 
    alternative to be less correct than the retention of the old behavior of kill ( ) in 
    such systems. Current conforming applications shall accommodate either behavior from 
    kill ( ), and there appears to be no strong reason for kill( ) to check the saved 
    set-user-ID rather than the effective user ID.

FUTUREDIRECTIONS

    None.

SEE ALSO

    exec, getegid( ), geteuid( ), getgid( ), getuid( ), setegid( ), seteuid( ), setgid( ), 
    setregid( ), setreuid( ), the Base Definitions volume of IEEE Std 1003.1-2001, 
    

CHANGE HISTORY

    First released in Issue 1. Derived from Issue 1 of the SVID.

Issue 6

    In the SYNOPSIS, the optional include of the header is removed.
    The following new requirements on POSIX implementations derive from alignment with the
    Single UNIX Specification:

      . The requirement to include has been removed. Although 
        was required for conforming implementations of previous POSIX specifications, it 
        was not required for UNIX applications.

      . The functionality associated with _POSIX_SAVED_IDS is now mandatory. This is a FIPS
        requirement.

    The following changes were made to align with the IEEE P1003.1a draft standard:

      . The effects of setuid( ) in processes without appropriate privileges are changed.

      . A requirement that the supplementary group list is not affected is added.
阅读(1357) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~