為了執行權限檢查,Linux 區分兩類程序:特權程序(其有效使用者辨別為 0,也就是超級使用者 root)和非特權程序(其有效使用者辨別為非零)。 特權程序繞過所有核心權限檢查,而非特權程序則根據程序憑證(通常為有效 UID,有效 GID 和補充組清單)進行完全權限檢查。
以常用的 passwd 指令為例,修改使用者密碼需要具有 root 權限,而普通使用者是沒有這個權限的。但是實際上普通使用者又可以修改自己的密碼,這是怎麼回事?在 Linux 的權限控制機制中,有一類比較特殊的權限設定,比如 SUID(Set User ID on execution),不了解 SUID 的同學請參考《Linux 特殊權限 SUID,SGID,SBIT》。因為程式檔案 /bin/passwd 被設定了 SUID 辨別,是以普通使用者在執行 passwd 指令時,程序是以 passwd 的所有者,也就是 root 使用者的身份運作,進而修改密碼。
SUID 雖然可以解決問題,卻帶來了安全隐患。當運作設定了 SUID 的指令時,通常隻是需要很小一部分的特權,但是 SUID 給了它 root 具有的全部權限。是以一旦 被設定了 SUID 的指令出現漏洞,就很容易被利用。也就是說 SUID 機制在增大了系統的安全攻擊面。
Linux 引入了 capabilities 機制對 root 權限進行細粒度的控制,實作按需授權,進而減小系統的安全攻擊面。本文将介紹 capabilites 機制的基本概念和用法。
說明:本文的示範環境為 Ubuntu 18.04。
從核心 2.2 開始,Linux 将傳統上與超級使用者 root 關聯的特權劃分為不同的單元,稱為 capabilites。Capabilites 作為線程(Linux 并不真正區分程序和線程)的屬性存在,每個單元可以獨立啟用和禁用。如此一來,權限檢查的過程就變成了:在執行特權操作時,如果程序的有效身份不是 root,就去檢查是否具有該特權操作所對應的 capabilites,并以此決定是否可以進行該特權操作。比如要向程序發送信号(kill()),就得具有 capability CAP_KILL;如果設定系統時間,就得具有 capability CAP_SYS_TIME。
下面是從 capabilities man page 中摘取的 capabilites 清單:
capability 名稱
描述
CAP_AUDIT_CONTROL
啟用和禁用核心審計;改變審計過濾規則;檢索審計狀态和過濾規則
CAP_AUDIT_READ
允許通過 multicast netlink 套接字讀取審計日志
CAP_AUDIT_WRITE
将記錄寫入核心審計日志
CAP_BLOCK_SUSPEND
使用可以阻止系統挂起的特性
CAP_CHOWN
修改檔案所有者的權限
CAP_DAC_OVERRIDE
忽略檔案的 DAC 通路限制
CAP_DAC_READ_SEARCH
忽略檔案讀及目錄搜尋的 DAC 通路限制
CAP_FOWNER
忽略檔案屬主 ID 必須和程序使用者 ID 相比對的限制
CAP_FSETID
允許設定檔案的 setuid 位
CAP_IPC_LOCK
允許鎖定共享記憶體片段
CAP_IPC_OWNER
忽略 IPC 所有權檢查
CAP_KILL
允許對不屬于自己的程序發送信号
CAP_LEASE
允許修改檔案鎖的 FL_LEASE 标志
CAP_LINUX_IMMUTABLE
允許修改檔案的 IMMUTABLE 和 APPEND 屬性标志
CAP_MAC_ADMIN
允許 MAC 配置或狀态更改
CAP_MAC_OVERRIDE
覆寫 MAC(Mandatory Access Control)
CAP_MKNOD
允許使用 mknod() 系統調用
CAP_NET_ADMIN
允許執行網絡管理任務
CAP_NET_BIND_SERVICE
允許綁定到小于 1024 的端口
CAP_NET_BROADCAST
允許網絡廣播和多點傳播通路
CAP_NET_RAW
允許使用原始套接字
CAP_SETGID
允許改變程序的 GID
CAP_SETFCAP
允許為檔案設定任意的 capabilities
CAP_SETPCAP
參考 capabilities man page
CAP_SETUID
允許改變程序的 UID
CAP_SYS_ADMIN
允許執行系統管理任務,如加載或解除安裝檔案系統、設定磁盤配額等
CAP_SYS_BOOT
允許重新啟動系統
CAP_SYS_CHROOT
允許使用 chroot() 系統調用
CAP_SYS_MODULE
允許插入和删除核心子產品
CAP_SYS_NICE
允許提升優先級及設定其他程序的優先級
CAP_SYS_PACCT
允許執行程序的 BSD 式審計
CAP_SYS_PTRACE
允許跟蹤任何程序
CAP_SYS_RAWIO
允許直接通路 /devport、/dev/mem、/dev/kmem 及原始塊裝置
CAP_SYS_RESOURCE
忽略資源限制
CAP_SYS_TIME
允許改變系統時鐘
CAP_SYS_TTY_CONFIG
允許配置 TTY 裝置
CAP_SYSLOG
允許使用 syslog() 系統調用
CAP_WAKE_ALARM
允許觸發一些能喚醒系統的東西(比如 CLOCK_BOOTTIME_ALARM 計時器)
getcap 指令和 setcap 指令分别用來檢視和設定程式檔案的 capabilities 屬性。下面我們示範如何使用 capabilities 代替 ping 指令的 SUID。
因為 ping 指令在執行時需要通路網絡,這就需要獲得 root 權限,正常的做法是通過 SUID 實作的(和 passwd 指令相同):

紅框中的 s 說明應用程式檔案被設定了 SUID,這樣普通使用者就可以執行這些指令了。
移除 ping 指令檔案上的 SUID 權限:
在移除 SUID 權限後,普通使用者在執行 ping 指令時碰到了 "ping: socket: Operation not permitted" 錯誤。
為 ping 指令檔案添加 capabilities
執行 ping 指令所需的 capabilities 為 cap_net_admin 和 cap_net_raw,通過 setcap 指令可以添加它們:
被賦予合适的 capabilities 後,ping 指令又可以正常工作了,相比 SUID 它隻具有必要的特權,在最大程度上減小了系統的安全攻擊面。
如果要移除剛才添加的 capabilities,執行下面的指令:
指令中的 ep 分别表示 Effective 和 Permitted 集合(接下來會介紹),+ 号表示把指定的 capabilities 添加到這些集合中,- 号表示從集合中移除(對于 Effective 來說是設定或者清除位)。
在上面的示例中我們通過 setcap 指令修改了程式檔案 /bin/ping 的 capabilities。在可執行檔案的屬性中有三個集合來儲存三類 capabilities,它們分别是:
Permitted
Inheritable
Effective
在程序執行時,Permitted 集合中的 capabilites 自動被加入到程序的 Permitted 集合中。
Inheritable 集合中的 capabilites 會與程序的 Inheritable 集合執行與操作,以确定程序在執行 execve 函數後哪些 capabilites 被繼承。
Effective 隻是一個 bit。如果設定為開啟,那麼在執行 execve 函數後,Permitted 集合中新增的 capabilities 會自動出現在程序的 Effective 集合中。
程序中有五種 capabilities 集合類型,分别是:
Bounding
Ambient
相比檔案的 capabilites,程序的 capabilities 多了兩個集合,分别是 Bounding 和 Ambient。
/proc/[pid]/status 檔案中包含了程序的五個 capabilities 集合的資訊,我們可以通過下面的命名檢視目前程序的 capabilities 資訊:
但是這中方式獲得的資訊無法閱讀,我們需要使用 capsh 指令把它們轉義為可讀的格式:
把特權使用者僅僅分為 root 和普通使用者顯然是過于粗糙了,這會帶來安全問題。Capabilities 為解決這一問題而生,它能提供精細粒度的特權集,進而有效的減小系統的安全攻擊面。
參考:
capability man page
Linux的capabilities機制
How Linux Capability Works in 2.6.25
getcap, setcap and file capabilities
Linux capabilities 101
getcap man page
setcap man page
作者:sparkdev
出處:http://www.cnblogs.com/sparkdev/
本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。