Linux進程概述

1、介紹linux

當linux系統中的一個進程運行起來的時候,老是要訪問系統的資源,訪問文件或者向其餘的進程發送信號。系統是否容許其進行這些操做?系統是根據什麼來判斷該進程的權限?這些問題是和進程信任狀(process credentials)相關。shell

process credentials包括一系列的ID,以下:編程

一、real user ID 和 real group ID網絡

二、effective user ID 和 effective group IDsession

三、saved set-user-ID 和 saved set-group-ID數據結構

四、file-system user ID 和 file-system group ID多線程

五、supplementary group IDsapp

 

2、什麼是real user ID 和 real group IDide

real user ID 和 real group ID標識了該進程屬於哪個用戶(哪個組)。Swapper和init進程的real user ID 和 real group ID都被設定爲root(ID=0),用戶登錄後,其對應的shell進程的real user ID 和 real group ID會被設定爲登陸用戶。這是login進程調用setuid函數設定的。在fork進程的時候,子進程的credentials是繼承自其父進程。函數

 

3、什麼是effective user ID 和 effective group ID

就如同其命名,真正去檢查一個進程是否有權限進行某些動做(例如訪問IPC對象、經過系統調用請求內核服務等)的是effective user ID 和 effective group ID。通常而言,effective user ID(effective group ID)是和real user ID(real group ID)同樣的,可是若是可執行文件設定了Set-User-ID(Set-Group-ID),那麼在進程建立的時候,其effective user ID 和 effective group ID則分別等於該可執行文件的user ID。

 

4、什麼是saved set-user-ID 和 saved set-group-ID

Linux kernel中的task_struct中定義了這些ID以下:

uid_t uid,euid,suid,fsuid;

gid_t gid,egid,sgid,fsgid;

這裏的suid(sgid)表示了saved set-user-ID(saved set-group-ID),這裏的變量命名很是不友好,表面看起來是save了real ID,但其實是save了effective ID。爲什麼要save effective ID?其實這是和一個準則相關的:一個進程應該以儘量小的權限運行。大部分的嵌入式軟件工程師都會忽略這一點,由於嵌入式系統基本不是多用戶的,開發者都是用root登陸進入系統,所有掌管一切。此外,saved set-user-ID(saved set-group-ID)是和Set-User-ID(Set-Group-ID)相關的。例如張三啓動一個owner是root的可執行程序,而且該程序設定了Set-User-ID bit,那麼,當該程序執行的時候,real user ID是張三,effective user ID是root,saved set-user-ID因爲是copy自effective user ID,所以也是root。該進程並非老是須要root權限,所以,基於進程應該以儘量小的權限運行的準則,在不需root權限的時候能夠經過系統調用修改effective user ID爲張三(對於unprivileged的用戶,effective user ID只能在real user ID和saved set-user-ID之間切換)。而在須要root權限的時候,能夠經過系統調用修改effective user ID回root。正由於如此,進程才須要一個saved set-user-ID來保存原始的effective user ID。

一樣的道理適用於saved set-group-ID,這裏再也不贅述。

 

5、什麼是file-system user ID 和 file-system group ID

這個ID是linux特有的,傳統的unix並無這個ID。對於傳統的unix,訪問文件、發送signal,打開IPC的object等等的權限都是依據effective ID判斷。對於linux,其他的權限仍然依據effective ID判斷,可是對於文件的訪問則使用file-system user ID 和 file-system group ID(固然,須要配合supplementary group IDs)。

在linux kernel中,file-system user ID(file-system group ID)都是跟隨effective user ID(effective group ID)。例如,若是owner是root的可執行文件若是設定了Set-User-ID bit,那麼,當該程序執行的時候, effective user ID是root,file-system user ID也跟隨effective user ID被設定爲root。若是經過系統調用修改effective user ID,file-system user ID也會隨之修改。這樣就保證了linux的權限判斷和傳統的unix是同樣的。不同的地方在於linux提供了兩個特別的系統調用setfsuid() 和setfsgid()來設定進程的file-system user ID和file-system group ID。

爲什麼linux要引入file-system user ID 和 file-system group ID?這是和NFS (Network File System)相關的。考慮下面的場景:運行NFS server進程的A主機開放其文件系統,運行NFS client進程的B主機能夠經過mount NFS file system象訪問本地文件那樣訪問A主機的文件。在這樣的場景下,NFS client進程訪問A主機上的文件固然應該應用NFS client的effective ID,可是因爲是網絡文件系統,實際訪問文件的是NFS server進程。若是修改NFS server的effective ID的話,用戶空間的進程能夠經過向NFS server發送signal來攻擊。解決這個問題有兩個思路:

一、  不修改effective ID,引入file-system user ID(file-system group ID)

二、  修改effective ID,改變信號發送的機制。也就是當A進程發送信號給B進程,該操做是否容許再也不和B進程的effective ID相關。

在linux kernel的早期版本採用了方案一,可是2.0以後的kernel版本採用了方案二。所以,file-system user ID 和 file-system group ID應該是被廢棄的,可是,爲了軟件的兼容性,linux kernel仍然保留了這兩個file-system ID。

 

6、什麼是supplementary group IDs

當一個用戶登陸後,loggin程序(其user ID是root)會根據/etc/passwd(還有/etc/shadow)中的信息來校驗密碼,並設定該登陸用戶的shell進程的user ID和第一個group ID。因爲一個用戶ID可能屬於多個group,經過/etc/group文件,loggin程序能夠知道該用戶還屬於哪些group,並設定該登陸用戶的shell進程的supplementary group IDs。

當用戶經過shell建立新的進程的時候,子進程的supplementary group IDs是繼承自其父進程。supplementary group IDs會配合file-system ID和effective ID來進行進程是否有訪問某些資源權限的斷定。

 

1、概述

本文主要描述在linux kernel中如何標識一個或者一組和進程(線程)相關的實體,包括:

一、進程ID(線程組ID)

二、線程ID

三、進程組ID

四、Session ID

須要強調的是本文focus在identification,不少展開的內容會有一系列文檔描述。

 

2、什麼是進程ID(線程組ID)

通常而言,咱們都會定義進程是一個正在執行的程序或者是一個程序的運行實例。程序是一個靜態的概念,是存儲在磁盤上的二進制可執行文件,包括程序代碼和數據(正文段、數據段等)。當程序運行起來成爲進程的時候,單純的程序代碼則不能清楚的描述進程,它還須要若干數據結構來描述程序的執行狀態(硬件上下文和軟件上下文)以及擁有的資源(如地址空間、打開的文件描述符等)。從內核的角度看,進程是一個和系統資源(CPU time、memory等)分配相關的實體。

在POSIX標準中,系統定義了getpid函數來獲取一個進程的process ID。在linux kernel中,定義以下:

asmlinkage long sys_getpid(void)

{

       return current->tgid;

}

從字面上看task_struct中的tgid是thread group ID,也就是線程組ID,在linux kernel中,進程是有一個或者多個thread組成(POSIX規定多個thread要共享一個進程ID)。對於linux kernel,每個thread分配一個task_struct(其中有一個pid的標識),這和大部分的kernel處理不同,其餘的kernel針對一個進程分配一個task_struct,在該task_struct中嵌入了屬於該進程的各個線程的數據。正由於如此,linux kernel建立一個線程組的概念來映射到POSIX中的進程概念。

多線程的進程中第一個線程(主線程,group leader)的pid等於tgid,以後,該線程組中的線程都有本身的pid,可是共享tgid,也就是傳統意義上的進程ID。task_struct有一個group_leader成員,指向該task的thread group leader,對於group leader,該成員指向本身的task_struct數據結構。

 

3、什麼是線程ID

線程是進程中的一個實體,是被系統獨立調度和分派的基本單位,線程本身不獨立擁有系統資源,它是與同屬一個進程的其它線程共享進程所擁有的所有資源(如地址空間、文件描述符和信號處理)。這首先表如今:全部線程都具備相同的地址空間(進程的地址空間),這意味着,線程能夠訪問該地址空間的每個虛地址;此外,還能夠訪問進程所擁有的已打開文件、定時器、信號量等資源。進程是資源管理的最小單元,而線程是程序執行的最小單元。除了共享的進程資源,進程中的各個線程也屬於本身的資源,具體包括:stack、PC counter和CPU寄存器。

每一個線程應該有本身的ID,就是線程ID,在linux kernel中,每個thread分配一個task_struct,該結構中的pid成員就是線程ID。在POSIX標準中,定義了pthread_self來獲取線程ID,linux kernel採用了gettid的系統調用來獲取調用者的線程ID。在linux kernel中,定義以下:

asmlinkage long sys_gettid(void)

{

       return current->pid;

}

POSIX規定線程ID在所屬進程中是惟一的,不過在linux kernel的實現中,thread ID是全系統惟一的,固然,考慮到可移植性,Application software不該該假設這一點。

 

4、什麼是進程組ID

每一個進程屬於一個進程組,每一個進程組有一個Leader進程,也就是進程ID等於進程組ID的那個進程。進程組有生命週期,它的生命週期開始於進程組leader建立進程組,結束於進程組內的最後一個進程離開進程組(多是進程退出, 或加入其餘進程組)。進程組概念的提出主要是因爲:

一、和job control相關,關於job control,後續會專門的文檔詳細描述。

二、 Signal能夠發送給進程組的每個進程(job control也使用這個特性。例如job control signal會被送給job(進程組)中的每個進程)

三、進程同步的時候,父進程能夠wait for進程組中的任何一個進程

在POSIX標準中,系統定義了getpgid函數來獲取一個進程的process group ID。在linux kernel中,定義以下:

asmlinkage long sys_getpgid(pid_t pid)

{

       if (!pid) {

        //若是pid等於0,那麼須要獲取當前進程的進程組ID

              return process_group(current);

    }

       else {

//不然,獲取pid標識的那個進程對應的進程組ID

              int retval;

              struct task_struct *p;

 

              read_lock(&tasklist_lock);

              p = find_task_by_pid(pid);

 

              retval = -ESRCH;

              if (p) {

            //是否有權利獲取其餘進程的進程組ID

                     retval = security_task_getpgid(p);

                     if (!retval)

                            retval = process_group(p);

              }

              read_unlock(&tasklist_lock);

              return retval;

       }

}

 

static inline pid_t process_group(struct task_struct *tsk)

{

       return tsk->signal->pgrp;

}

task_struct中的signal中的pgrp成員標識了進程組ID。從pgrp的位置來看,進程組應該是和信號處理相關的,後續會專門的文檔詳細描述。

 

5、Session ID

和進程屬於進程組相似,每一個進程組都屬於一個session,每一個session有一個Leader進程,也就是建立session的那個進程,session leader的ID就等於該session的ID。Session概念的提出和用戶登陸以及終端編程相關,後續會專門的文檔詳細描述。

在POSIX標準中,系統定義了getsid函數來獲取session leader進程的process group ID。若是指定的PID不是session leader,將返回錯誤,可是在linux kernel中沒有徹底遵照這個規定,getsid函數老是能返回指定PID的session ID,不管該PID指向的進程是不是session leader,具體定義以下:

asmlinkage long sys_getsid(pid_t pid)

{

       if (!pid) {

        //若是pid等於0,那麼須要獲取當前進程的進程組ID

              return process_session(current);

    }

       else {

//不然,獲取pid標識的那個進程對應的進程組ID

              int retval;

              struct task_struct *p;

 

              read_lock(&tasklist_lock);

              p = find_task_by_pid(pid);

 

              retval = -ESRCH;

              if (p) {

                     retval = security_task_getsid(p);

                     if (!retval)

                            retval = process_session(p);

              }

              read_unlock(&tasklist_lock);

              return retval;

       }

}

static inline pid_t process_session(struct task_struct *tsk)

{

       return signal_session(tsk->signal);

}

static inline pid_t signal_session(struct signal_struct *sig)

{

       return sig->__session;

}

task_struct中的signal中的__session成員標識了進程組ID。從__session的位置來看,session應該也是和信號處理相關的,後續會詳細描述。

相關文章
相關標籤/搜索