Linux 許可權控制的基本原理

發表於2018-06-13

這裡,我們主要介紹 Linux 系統中,許可權控制的基本原理。

安全模型

Linux 系統中,我們所有的操作實質都是在進行程式訪問檔案的操作。我們訪問檔案需要先取得相應的訪問許可權,而訪問許可權是通過 Linux 系統中的安全模型獲得的。

對於 Linux 系統中的安全模型,我們需要知道下面兩點

  1. Linux 系統上最初的安全模型叫 DAC, 全稱是 Discretionary Access Control ,翻譯為自主訪問控制。
  2. 後來又增加設計了一個新的安全模型叫 MAC, 全稱是 Mandatory Access Control, 翻譯為強制訪問控制。

注意, MACDAC 不是互斥的, DAC 是最基本的安全模型,也是通常我們最常用到的訪問控制機制是 Linux 必須具有的功能, 而 MAC 是構建在 DAC 之上的加強安全機制,屬於可選模組。訪問前, Linux系統通常都是先做 DAC 檢查, 如果沒有通過則操作直接失敗; 如果通過 DAC 檢查並且系統支援 MAC 模組,再做 MAC 許可權檢查。

為區分兩者,我們將支援 MACLinux 系統稱作 SELinux, 表示它是針對 Linux 的安全加強系統。

這裡,我們將講述 Linux 系統中的 DAC 安全模型。

DAC 安全模型

DAC 的核心內容是:在 Linux 中,程式理論上所擁有的許可權與執行它的使用者的許可權相同。其中涉及的一切內容,都是圍繞這個核心進行的。

使用者和組ID資訊控制

使用者、組、口令資訊

通過 /etc/passwd/etc/group 儲存使用者和組資訊,通過 /etc/shadow 儲存密碼口令及其變動資訊, 每行一條記錄。

使用者和組分別用 UIDGID 表示,一個使用者可以同時屬於多個組,預設每個使用者必屬於一個與之 UID 同值同名的 GID

對於 /etc/passwd , 每條記錄欄位分別為 使用者名稱:口令(在 /etc/shadow 加密儲存):UID:GID(預設UID):描述註釋:主目錄:登入shell(第一個執行的程式)

對於 /etc/group , 每條記錄欄位分別為 組名:口令(一般不存在組口令):GID:組成員使用者列表(逗號分割的使用者UID列表)

對於 /etc/shadow ,每條記錄欄位分別為: 登入名:加密口令:最後一次修改時間:最小時間間隔:最大時間間隔:警告時間:不活動時間:

舉例

以下是對使用者和組資訊的舉例。 /etc/shadow 中的口令資訊為加密儲存,不舉例。

檔案許可權控制資訊

檔案型別

Linux 中的檔案有如下型別:

  • 普通檔案, 又包括文字檔案和二進位制檔案, 可用 touch 建立;
  • 套接字檔案, 用於網路通訊,一般由應用程式在執行中間接建立;
  • 管道檔案是有名管道,而非無名管道, 可用 mkfifo 建立;
  • 字元檔案和塊檔案均為裝置檔案, 可用 mknod 建立;
  • 連結檔案是軟連結檔案,而非硬連結檔案, 可用 ln 建立。

訪問許可權控制組

分為三組進行控制:

  • user 包含對檔案屬主設定的許可權
  • group 包含對檔案屬組設定的許可權
  • others 包含對其他者設定的許可權

可設定的許可權

下面給出常見(但非全部)的許可權值, 包括:

  • r 表示具有讀許可權。
  • w 表示具有寫許可權。
  • x 一般針對可執行檔案/目錄,表示具有執行/搜尋許可權。
  • s 一般針對可執行檔案/目錄,表示具有賦予檔案屬主許可權的許可權,只有 usergroup 組可以設定該許可權。
  • t 一般針對目錄,設定粘滯位後,有許可權的使用者只能寫、刪除自己的檔案,否則可寫、刪除目錄所有檔案。舊系統還表示可執行檔案執行後將text拷貝到交換區提升速度。

舉例

通過 ls -l 可以檢視到其檔案型別及許可權,通過 chmod 修改許可權。

舉例來說,

輸出中, 第1個字元表示檔案型別,其中,普通檔案(-)、目錄檔案 (d)、套接字檔案(s),管道檔案(p),字元檔案(c),塊檔案(b),連結檔案(l); 第2個字元開始的 -rwxr-xr-x 部分表示檔案的許可權位,共有9位。

對於檔案 /usr/bin/qemu-i386 , 這個許可權控制的含義是:

  1. 第2~4位的 rwx 表示該檔案可被它的 owner (屬主)以 rwx 的許可權訪問。
  2. 第5~7位的 r-x 表示該檔案可被與該檔案同一屬組的使用者以 rx 的許可權訪問
  3. 第8~10位的 r-x 表示該檔案可被其它未知使用者以 rx 的許可權訪問。

對於 test/, test2/, test3/ 設定的許可權:

  1. r,w,x 許可權對每一許可權控制組的許可權用一位8進位制來表示; 例如: 755 表示 rwxr-xr-x
  2. s,t 許可權會替代 x 位置顯示;設定 s,t 許可權則需在對應的、用於控制 r,w,x 的8進位制許可權控制組前追加數字; s 許可權用於屬主屬組控制, t 用於其它控制。
  3. 設定屬主 s 需追加 4, 設定屬組 s 追加 2, 設定其它者 t 許可權追加 1 ; 例如前面對 test/ 設定 t, 則用 1775, 表示 rwxrwxr-t

程式許可權控制資訊

程式許可權

對於程式,有如下屬性與檔案訪問許可權相關:

  • effective user id : 程式訪問檔案許可權相關的 UID (簡寫為 euid )。
  • effective group id : 程式訪問檔案許可權相關的 GID (簡寫為 egid )。
  • real user id : 建立該程式的使用者登入系統時的 UID (簡寫為 ruid )。
  • real group id : 建立該程式的使用者登入系統時的 GID (簡寫為 rgid )。
  • saved set user id : 拷貝自 euid
  • saved set group id : 拷貝自 egid

舉例

我們可以使用 pstop 選擇檢視具有 euidruid 的程式。或者通過 top 來檢視程式的 euidruid

通過 top 來檢視的例子:

  1. 首先輸入 top 得到類似如下

    這裡通過 -d 選項延長 top 的重新整理頻率便於操作。此處可見,只有 USER 欄位,表示相應程式的 effective user id.
  2. 開啟 read user id 的顯示選項
    1. top 命令執行期間,輸入 f, 可以看見類似如下行:
    2. 輸入 c 即可開啟 Real user name 的顯示開關。
    3. 最後 Return 回車回到 top 中,即可看到 real user id 的選項此時輸入 o,可調整列次序最終我們可看到包含 effective user idreal user id 的輸出如下:

      其中, PID 是對應程式, USER 是對應的 effective user, RUSER 是對應的 real user

程式訪問檔案的許可權控制策略

規則

程式訪問檔案大致許可權控制策略

對於程式訪問檔案而言,最重要的是 euid, 所以其許可權屬性均以 euid 為 “中心”。

  • 程式的 euid 一般預設即為 其 ruid
  • 若可執行檔案的可執行許可權位為 s ,程式對其呼叫 exec 後,其 euid 被設定為該可執行檔案的 user id
  • 程式的 saved set user id 拷貝自 euid.
  • 當程式的 euid 與檔案的 user id 匹配時,程式才具有檔案 user 許可權位所設定的許可權
  • 組許可權 egid 的控制規則類似。
通過 exec 執行檔案修改許可權屬性

通過 exec 呼叫可執行檔案之時:

  • 程式 ruid 值始終不變;
  • saved set-user ID 始終來自 euid
  • euid 值取決於檔案的 set-user-ID 位是否被設定。

如下:

ID set-user-ID bit off set-user-ID bit on
real user ID unchanged unchanged
effective user ID unchanged set from userID of program file
saved set-user ID copied from effective user ID copied from effective user ID
通過 setuid(uid) 系統呼叫修改許可權屬性

通過 setuid(uid) 修改許可權屬性之時:

  • superuser 可順利修改 ruid, euid, saved set-user ID
  • unprivileged user 只能在 uidruid 相等時修改 euid, 其它無法修改。

如下:

ID superuser unprivileged user
real user ID set to uid unchanged
effective user ID set to uid set to uid
saved set-user ID set to uid unchanged

舉例

再舉幾個比較特別的例子:

設定了 set-user-id

如前所述,這個輸出的含義是,對於 /usr/bin/sudo 檔案,

  • 第1~3位的 rws 表示該檔案可被它的owner(屬主)以 rws 的許可權訪問
  • 第4~6位的 r-x 表示該檔案可被與該檔案同一屬組的使用者以 rx 的許可權訪問。
  • 第7~9位的 r-x 表示該檔案可被其它未知使用者以 rx 的許可權訪問。

這樣設定之後,對於owner,具有讀、寫、執行許可權,這一點沒有什麼不同。但是對於不屬於 root 組的普通使用者程式來說,卻大不相同。

普通使用者程式執行 sudo 命令時通過其 others 中的 x 獲得執行許可權,再通過 user 中的 s 使得普通使用者程式臨時具有了 sudo 可執行檔案屬主( root )的許可權,即超級許可權。

這也是為什麼通過 sudo 命令就可以讓普通使用者執行許多管理員許可權的命令的原因。

設定了 stick-bit

這樣設定之後,對於 /tmp 目錄,任何人都具有讀、寫、執行許可權,這一點沒有什麼不同。但是對於 others 部分設定了粘滯位 t, 其功能卻大不相同。

若目錄沒設定粘滯位,任何對目錄有寫許可權者都則可刪除其中任何檔案和子目錄,即使他不是相應檔案的所有者,也沒有讀或寫許可; 設定粘滯位後,使用者就只能寫或刪除屬於他的檔案和子目錄。

這也是為什麼任何人都能向 /tmp 目錄寫檔案、目錄,卻只能寫和刪除自己擁有的檔案或目錄的原因。

舉一個 man 程式的應用片斷,描述 set-user-idsaved set-user-id 的使用

man 程式可以用來顯示線上幫助手冊, man 程式可以被安裝指定 set-user-ID 或者 set-group-ID 為一個指定的使用者或者組。

man 程式可以讀取或者覆蓋某些位置的檔案,這一般由一個配置檔案(通常是 /etc/man.config 或者 /etc/manpath.config )或者命令列選項來進行配置。

man 程式可能會執行一些其它的命令來處理包含顯示的 man 手冊頁的檔案。

為防止處理出錯, man 會從兩個特權之間進行切換:執行 man 命令的使用者特權,以及 man 程式的擁有者的特權。

需要抓住的主線:當只執行 man 之時,程式特權就是 man 使用者的特權, 當通過 man 執行子程式(如通過 !bash 引出shell命令)時,使用者切換為當前使用者,執行完又切換回去。

過程如下:

  1. 假設 man 程式檔案被使用者 man 所擁有,並且已經被設定了它的 set-user-ID 位,當我們 exec 它的時候,我們有如下情況:
    • real user ID = 我們的使用者UID
    • effective user ID = man使用者UID
    • saved set-user-ID = man使用者UID
  2. man 程式會訪問需要的配置檔案和 man 手冊頁。這些檔案由 man 使用者所擁有,但是由於 effective user IDman,檔案的訪問就被允許了。
  3. man 為我們執行任何命令的時候,它會呼叫 setuid(getuid())) (getuid() 返回的是 real user id).因為我們不是 superuser 程式,這個變化只能改變 effective user ID. 我們會有如下情況:
    • real user ID = 我們的使用者UID(不會被改變)
    • effective user ID = 我們的使用者UID
    • saved set-user-ID = man 的使用者UID(不會被改變)

    現在 man 程式執行的時候把我們得UID作為它的 effective user ID.這也就是說,我們只能訪問我們擁有自己許可權的檔案。也就是說,它能夠代表我們安全地執行任何 filter.

  4. filter 做完了的時候, man 會呼叫 setuid(euid).這裡, euidman 使用者的UID.(這個ID是通過 man 呼叫 geteuid 來儲存的)這個呼叫是可以的,因為 setuid 的引數和 saved set-user-ID 是相等的。(這也就是為什麼我們需要 saved set-user-ID).這時候我們會有如下情況:
    • real user ID = 我們的使用者UID(不會被改變)
    • effective user ID = man的UID
    • saved set-user-ID = man 的使用者UID(不會被改變)
  5. 由於 effective user IDman,現在 man 程式可以操作它自己的檔案了。通過這樣使用 saved set-user-ID,我們可以在程式開始和結束的時候通過程式檔案的 set-user-ID 來使用額外的許可權。然而,期間我們卻是以我們自己的許可權執行的。如果我們無法在最後切換回 saved set-user-ID,我們就可能會在我們執行的時候保留額外的許可權。

下面我們來看看如果 man 啟動一個 shell 的時候會發生什麼:

  • 這裡的 shellman 使用 forkexec 來啟動的。
  • 因為這時 real user IDeffective user ID 都是我們的普通使用者UID(參見step3), 所以 shell 沒有其它額外的許可權.
  • 啟動的 shell 無法訪問 mansaved set-user-ID(man) ,因為 shellsaved set-user-ID 是由 execeffective user ID 拷貝過來的。
  • 在執行 exec 的子程式( shell )中,所有的 user ID 都是我們的普通使用者ID.

實際上,我們描述 man 使用 setuid 函式的方法不是特別正確,因為程式可能會 set-user-IDroot .這時候, setuid 會把所有三種uid都變成你設定的id,但是我們只需要設定 effective user ID.

相關文章