TLPI-Chapter 9 進程憑證

這一章開始看的有點懵,在網上搜索到一篇文章有助於理解鏈接地址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的進程屬特權級進程。換言之,對於進程發起的各種系統調用,可免於接受通常所要經歷的諸多權限檢查。

發佈了128 篇原創文章 · 獲贊 40 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章