在學習 Linux 系統權限相關的主題時,咱們首先關注的基本都是文件的 ugo 權限。ugo 權限信息是文件的屬性,它指明瞭用戶與文件之間的關係。可是真正操做文件的倒是進程,也就是說用戶所擁有的文件訪問權限是經過進程來體現的。本文主要介紹進程的權限,並經過示例解釋用戶身份與進程權限之間的關係。說明:本文的演示環境爲 ubuntu 16.04。html
用戶
對於支持多任務的 Linux 系統來講,用戶就是獲取資源的憑證。shell
權限
權限用來控制用戶對計算機資源(CPU、內存、文件等)的訪問,通常會分爲認證和受權兩步。好比用戶先通過認證機制(authentication)登陸系統,而後由受權系統(authorization)對用戶的操做進行受權。ubuntu
進程
進程是任何支持多道程序設計的操做系統中的基本概念。一般把進程定義爲程序執行時的一個實例。所以,若是有 10 個用戶同時運行 vi,就會有 10 個獨立的進程(儘管它們共享同一份可執行代碼)。
實際上,是進程在幫助咱們完成各類任務。進程就是用戶訪問計算機資源的代理,用戶執行的操做實際上是帶有用戶身份信息的進程執行的操做。bash
進程權限
既然是進程在爲用戶執行具體的操做,那麼當用戶要訪問系統的資源時就必須給進程賦予權限。也就是說進程必須攜帶發起這個進程的用戶的身份信息纔可以進行合法的操做。函數
在 Linux 系統啓動後,init 系統會 fork 出子進程執行 /sbin/getty 程序等待用戶登陸。當用戶進行登陸操做時,該子進程經過 exec 函數開始執行 /bin/login 程序(此時該進程已經變成了 login 進程)。由 login 進程驗證咱們的用戶名和密碼並查詢 /etc/passwd 和 /etc/shadow 肯定其合法性。若是是合法的用戶,該進程再次經過 exec 函數執行用戶的默認 shell 程序,此時的 login 進程就變成了 shell 進程(筆者機器上是 bash 進程)。而且該 shell 進程的有效身份被設置成爲該用戶的身份,以後 fork 此 shell 進程的子進程都會繼承該有效身份。咱們能夠經過下圖來理解用戶從 tty 登陸系統的過程(此圖來自互聯網):學習
上圖描述了 init 進程、getty 進程、login 進程和 shell 進程的交互。
簡單點說就是:用戶登陸後, shell 進程的有效用戶就是該用戶。下面咱們來了解下進程的用戶信息。ui
經過 cat /proc/<PID>status 命令,咱們能夠查看到進程所屬的用戶和組相關的信息:spa
經過 man proc 能夠查詢到第一行的四個數字分別是 real user id, effective user id, saved set user id 和 filesystem UID,第二行則是對應的組 ID。這裏咱們只介紹第一行中的前三個 ID,即 real user id, effective user id 和 saved set user id。操作系統
real user id
real user id 是執行進程者的 user id,通常狀況下就是用戶登陸時的 user id。子進程的 real user id 從父進繼承。一般這個是不更改的,也不須要更改。好比我以用戶 nick 登陸 Linux 系統,我接下來運行的全部命令的進程的 real user id 都是 nick 的 user id。.net
effective user id
若是要判斷一個進程是否對某個文件有操做權限,驗證的是進程的 effective user id,而不是 real user id。
一般咱們是不建議直接使用 root 用戶進行操做的,可是在不少狀況下,程序可能須要特殊的權限。好比 passwd 程序須要 root 權限纔可以爲普通用戶修改密碼,一些 services 程序的操做也常常須要特殊的權限。爲此,Linux 中設計了一些特殊的權限,請參考《Linux 特殊權限 SUID,SGID,SBIT》一文。這裏咱們以 passwd 程序爲例,爲二進制可執行文件 /usr/bin/passwd 設置 set-user-id bit=ON,這個可執行文件被用 exec 啓動以後的進程的 effective user id 就是這個可執行文件的 owner id,而並不是父進程的 real user id。若是 set-user-id bit=OFF 的時候,這個被 exec 起來的進程的 effective user id 應該是等於進程的 user id 的。因此,effective user id 存在的意義在於,它可能和 real user id 不一樣。
saved set user id
saved set user id 至關因而一個 buffer,在 exec 函數啓動以後,它會拷貝 effective user id 位的信息覆蓋本身。對於非 root 用戶來講,能夠在將來使用 setuid() 函數將 effective user id 設置成爲 real user id 或 saved set user id 中的任何一個。可是不容許非 root 用戶用 setuid() 函數把 effective user id 設置成爲任何第三個 user id。
對於 root 用戶來講,調用 setuid() 的時候,將會設置全部的這三個 user id。
從整體上來看,進程中 real user id, effective user id 和 saved set user id 的設計是爲了讓 unprivilege user 能夠得到兩種不一樣的權限。同時咱們也能夠得出下面的結論:
Linux 系統經過進程的有效用戶 ID(effective user id) 和有效用戶組 ID(effective group id) 來決定進程對系統資源的訪問權限。
其實咱們經過 ps aux 查看的結果中,第一列顯示的就是進程的 effective user:
在 shell 中執行的命令分爲內部命令和外部命令兩種。
外部命令的執行過程以下:
咱們經過下面的例子來理解在 shell 中執行外部命令的過程,例子很簡單就是經過 cat 命令查看一個文本文件 test.log:
$ cat test.log
咱們先來檢查一下當前用戶以及相關文件的權限:
當前用戶 nick 的 real user id 爲 1000,/bin/cat 文件的全部者爲 root,可是全部人都有執行權限,test.log 文件的全部者爲 nick。咱們結合下圖來介紹 cat test.log 命令的執行過程:
當咱們在 shell 中執行一個外部程序的時候,默認狀況下進程的 effective user ID 等於 real user ID,進程的 effective group ID 等於 real group ID(接下來的介紹中省略 group ID)。當咱們以用戶 nick 登陸系統,並在 bash 中鍵入 cat test.log 命令並回車後。Bash 先經過 fork() 創建一個新的子進程,這個新的子進程是當前 bash 進程的一個副本。新的進程在 PATH 變量指定的路徑中搜索 cat 程序,找到 /bin/cat 程序後檢查其權限。/bin/cat 程序的全部者爲 root,可是其餘人具備讀和執行的權限,因此新進程能夠經過 exec 函數用 cat 程序的代碼段替換當前進程中的代碼段(把 /bin/cat 程序加載到了內存中,此時的進程已經變成了 cat 進程,cat 進程會從 _start 函數開始執行)。因爲 cat 進程是由用戶 nick 啓動的,因此 cat 進程的 effective user ID 是 1000(nick)。同時 cat 進程的 effective user ID 和 test.log 文件的 owner ID 相同(都是 1000),因此 cat 進程擁有對此文件的 rw- 權限,那麼瓜熟蒂落地就能夠讀寫 test.log 文件的內容了。
下面咱們演示一個經過設置特殊權限 set uid ID 改變進程 effective user ID 的例子。
建立文件 root.log,權限爲 640,此時只有 root 有權限讀寫該文件的內容,用戶 nick 連讀取該文件的權限都沒有:
而後經過設置特殊權限 set uid ID 讓運行 cat 程序的進程具備 root 權限:
$ sudo chmod 4755 /bin/cat
如今能夠了!由於運行 cat 程序的進程的 effective user ID 變成了 root。記得要把 /bin/cat 的權限改回去呀:
$ sudo chmod 755 /bin/cat
在 shell 中執行腳本的方式和執行外部命令的方式差很少,好比咱們要執行下面的腳本:
$ /bin/bash ./test.sh
這時一樣會 fork 出一個子進程。只不過腳本與程序相比沒有代碼段,也沒有 _start 函數,此時 exec 函數就會執行另一套機制。好比咱們在 test.sh 文件的第一行經過 #!/bin/bash 指定了一個解釋器,那麼解釋器程序的代碼段會用來替換當前進程的代碼段,而且從解釋器的 _start 函數開始執行,而這個文本文件被看成命令行參數傳給解釋器。因此上面的命令執行過程爲:Bash 進程 fork/exec 一個子 bash 進程用於執行腳本,子 bash 進程繼承父進程的環境變量、用戶信息等內容,父進程等待子 bash 進程終止。
文件上的權限信息和用戶的信息都是靜態的,而進程是動態的,它把自身攜帶的用戶信息和將要進行的操做結合起來,從而實現權限管理。至此咱們也基本上搞明白了 Linux 權限系統的工做原理。
參考:
Linux基礎:用戶身份與進程權限
深入理解——real user id, effective user id, saved user id in Linux