您的位置:首页 > 其它

TLPI-Chapter 9 进程凭证

2017-10-22 15:25 267 查看
这一章开始看的有点懵,在网上搜索到一篇文章有助于理解链接地址Set-User-ID

1.每个进程都有一套用数字表示的用户ID和组ID。具体有实际用户ID(real user ID), 实际组ID(real group ID),有效用户ID(effective user ID),有效组ID(effective group ID),保存的set-user-ID和set-group-ID,文件系统用户ID和文件系统组ID,辅助组ID。

将上述种种ID称为进程凭证。

2.实际用户ID和实际组ID:

这两个ID确定了进程所属的用户和组。当用户登录时,会从/etc/passwd文件中读取UID和GID作为实际用户ID和组ID,后续创建的进程都从父进程处继承实际 UID和实际 GID。

3.有效用户ID和有效组ID:

进程尝试访问各种资源时,系统会依据有效用户ID和有效组ID连同辅助组ID一起来确定授予该进程的权限。

有效用户ID为0的用进程拥有的超级用户的所有权限。这样的进程称之为特权级进程,某些系统调用只能由特权级进程执行。

一般有效ID等实际ID,但会有一些操作导致这两种不一样。

4.set-user-id 和 set-group-id程序

set-user-id程序可以将进程的有效id修改为文件属主的ID,从而获得常规情况下并不具有的权限。set-group-id实现同样的功能。比如sudo就可以暂时获得root的权限。

可以使用chmod命令来设置权限位:

chmodu+sprog chmod g+s prog

$ ls -l prog

-rwsr-sr-x 1 root root 302585 Jun 26 15:05 prog

可以发现设置set-user-id后,x标志位别替换为s,当运行set-user-id进程时,内核会将该进程的UID设置为该文件属主的UID,则该进程拥有了对该文件的所有权限。同样推理可知,如果一个文件的属主为root,并且该文件可以设置set-user-id,则某个进程调用set-user-id时,内核就会将该进程的有效ID设置为0(root),则该进程暂时取得了root权限。注意修改的是进程的ID,不是文件的ID。

5.保存set-user-id 和保存set-group-id.

当set-user-id时,会发生如下步骤:

1.若可执行文件的set-user-id权限位已开,则将进程的有效用户ID设置为文件的属主ID,若没开启,则进程的有效ID保持不变。

2.保存set-user-id和保存set-group-id的值由对应的有效ID复制而来,无论正在执行的文件是否设置了set-user-id,复制都会进行。

举例说明:

假设某进程的实际id,有效id,保存的set-user-id都为1000,当其执行了root用户的拥有set-user-id的程序后,进程的ID会发生如下变化:

real=1000 effective=0 saved=0

有不少系统调用,允许将set-user-id程序的有效用户id和实际用户id来回切换,则saved就是为了保存effective的副本。

6.文件系统用户id和组id

在linux系统中,要进行诸如打开文件,改变文件属主,修改文件权限之类的文件系统操作,决定其操作权限的是文件系统用户id和组id。一般文件系统id和有效id是一致的。只有当使用linux的两个系统调用setfsuid()和setfsgid()时才会不一样。

7.获取和修改进程凭证



示例程序

/*************************************************************************\
*                  Copyright (C) Michael Kerrisk, 2015.                   *
*                                                                         *
* This program is free software. You may use, modify, and redistribute it *
* under the terms of the GNU General Public License as published by the   *
* Free Software Foundation, either version 3 or (at your option) any      *
* later version. This program is distributed without any warranty.  See   *
* the file COPYING.gpl-v3 for details.                                    *
\*************************************************************************/

/* Listing 9-1 */

/* idshow.c

Display all user and group identifiers associated with a process.

Note: This program uses Linux-specific calls and the Linux-specific
file-system user and group IDs.
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/fsuid.h>
#include <limits.h>
#include "ugid_functions.h"   /* userNameFromId() & groupNameFromId() */
#include "tlpi_hdr.h"

#define SG_SIZE (NGROUPS_MAX + 1)

int
main(int argc, char *argv[])
{
uid_t ruid, euid, suid, fsuid;
gid_t rgid, egid, sgid, fsgid;
gid_t suppGroups[SG_SIZE];
int numGroups, j;
char *p;

if (getresuid(&ruid, &euid, &suid) == -1)
errExit("getresuid");
if (getresgid(&rgid, &egid, &sgid) == -1)
errExit("getresgid");

/* Attempts to change the file-system IDs are always ignored
for unprivileged processes, but even so, the following
calls return the current file-system IDs */

fsuid = setfsuid(0);
fsgid = setfsgid(0);

printf("UID: ");
p = userNameFromId(ruid);
printf("real=%s (%ld); ", (p == NULL) ? "???" : p, (long) ruid);
p = userNameFromId(euid);
printf("eff=%s (%ld); ", (p == NULL) ? "???" : p, (long) euid);
p = userNameFromId(suid);
printf("saved=%s (%ld); ", (p == NULL) ? "???" : p, (long) suid);
p = userNameFromId(fsuid);
printf("fs=%s (%ld); ", (p == NULL) ? "???" : p, (long) fsuid);
printf("\n");

printf("GID: ");
p = groupNameFromId(rgid);
printf("real=%s (%ld); ", (p == NULL) ? "???" : p, (long) rgid);
p = groupNameFromId(egid);
printf("eff=%s (%ld); ", (p == NULL) ? "???" : p, (long) egid);
p = groupNameFromId(sgid);
printf("saved=%s (%ld); ", (p == NULL) ? "???" : p, (long) sgid);
p = groupNameFromId(fsgid);
printf("fs=%s (%ld); ", (p == NULL) ? "???" : p, (long) fsgid);
printf("\n");

numGroups = getgroups(SG_SIZE, suppGroups);
if (numGroups == -1)
errExit("getgroups");

printf("Supplementary groups (%d): ", numGroups);
for (j = 0; j < numGroups; j++) {
p = groupNameFromId(suppGroups[j]);
printf("%s (%ld) ", (p == NULL) ? "???" : p, (long) suppGroups[j]);
}
printf("\n");

exit(EXIT_SUCCESS);
}


总结:

每个进程都有一干与之相关的用户ID和组ID。实际ID定义了进程所属。在大多数UNIX实现中,进程对诸如文件之类资源的访问,其许可权限由有效ID决定。然后Linux会使用文件系统ID来决定对文件的访问权限,而将有效ID用于检查其它权限。进程辅助组ID则时由出于权限检查目的而另行设立的进程属组集合。存在各种系统调用和库函数支持进程获取和修改其用户ID和组ID。

set-user-ID程序运行时,会将进程有效用户ID设置为文件属主的用户ID。运行某个特殊程序时,这种机制支持用户假借其它用户的身份和特权。相应的,set-group-ID程序会修改运行改程序的进程的有效组ID。保存set-user-ID和保存set-group-ID允许set-user-ID和set-group-ID程序临时性的放弃特权,并在之后恢复特权。

0在用户ID中卓尔不群。通常仅为一个名为root的账号所有。有效用户ID为0的进程属特权级进程。换言之,对于进程发起的各种系统调用,可免于接受通常所要经历的诸多权限检查。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  TLPI 进程凭证