Perf 事件和工具安全性¶
概述¶
使用 Linux 的效能計數器 (perf_events) [1] , [2] , [3] 可能會帶來相當大的風險,導致被監控程序訪問的敏感資料洩露。無論是在直接使用 perf_events 系統呼叫 API [2] 的情況下,還是透過 Perf 工具使用者模式實用程式 (Perf) 生成的資料檔案 [3] , [4] ,都可能發生資料洩露。風險取決於 perf_events 效能監控單元 (PMU) [2] 和 Perf 收集並公開用於效能分析的資料的性質。收集的系統和效能資料可以分為幾個類別
系統硬體和軟體配置資料,例如:CPU 型號及其快取配置,可用記憶體量及其拓撲結構,使用的核心和 Perf 版本,效能監控設定,包括實驗時間,事件配置,Perf 命令列引數等。
使用者和核心模組路徑及其載入地址和大小,程序和執行緒名稱及其 PID 和 TID,捕獲的硬體和軟體事件的時間戳。
核心軟體計數器的內容(例如,用於上下文切換,頁面錯誤,CPU 遷移),架構硬體效能計數器 (PMC) [8] 和特定於機器的暫存器 (MSR) [9] ,它們提供系統各個受監控部分的執行指標(例如,記憶體控制器 (IMC),互連 (QPI/UPI) 或外圍 (PCIe) uncore 計數器),而無需直接歸因於任何執行上下文狀態。
架構執行上下文暫存器的內容(例如,x86_64 上的 RIP,RSP,RBP),程序使用者和核心空間記憶體地址和資料,捕獲此類資料的各種架構 MSR 的內容。
屬於第四類的資料可能包含敏感的程序資料。 如果 PMU 在某些監控模式下捕獲執行上下文暫存器或來自程序記憶體的資料的值,則對此類監控模式的訪問需要正確排序和保護。 因此,perf_events 效能監控和可觀察性操作是安全訪問控制管理的主題 [5] 。
perf_events 訪問控制¶
為了執行安全檢查,Linux 實現將程序分為兩類 [6] :a) 特權程序(其有效使用者 ID 為 0,稱為超級使用者或 root),以及 b) 非特權程序(其有效 UID 不為零)。 特權程序繞過所有核心安全許可權檢查,因此 perf_events 效能監控完全可用於特權程序,而沒有訪問,範圍和資源限制。
非特權程序需要根據程序的憑據 [5] (通常:有效 UID,有效 GID 和補充組列表)進行完整的安全許可權檢查。
Linux 將傳統上與超級使用者相關聯的特權劃分為不同的單元,稱為 capabilities [6],可以針對非特權使用者的程序和檔案在每個執行緒的基礎上獨立啟用和停用。
啟用 CAP_PERFMON capability 的非特權程序在 perf_events 效能監控和可觀察性操作方面被視為特權程序,因此繞過核心中的範圍許可權檢查。 CAP_PERFMON 實現了核心中效能監控和可觀察性操作的最小特權原則 [13] (POSIX 1003.1e: 2.2.2.39),並提供了一種安全的系統性能監控和可觀察性方法。
出於向後相容性的原因,CAP_SYS_ADMIN 特權程序也可以訪問 perf_events 監控和可觀察性操作,但不建議將 CAP_SYS_ADMIN 用於安全監控和可觀察性用例,而應使用 CAP_PERFMON capability。 如果使用 perf_events 系統呼叫 API 的程序的系統審計記錄 [14] 包含拒絕獲取 CAP_PERFMON 和 CAP_SYS_ADMIN capability 的記錄,則建議僅為該程序提供 CAP_PERFMON capability,作為解決與使用效能監控和可觀察性相關的雙重訪問拒絕日誌記錄的首選安全方法。
在 Linux v5.9 之前,使用 perf_events 系統呼叫的非特權程序還需要進行 PTRACE_MODE_READ_REALCREDS ptrace 訪問模式檢查 [7],其結果決定是否允許監控。 因此,提供 CAP_SYS_PTRACE capability 的非特權程序實際上被允許透過檢查。 從 Linux v5.9 開始,不需要 CAP_SYS_PTRACE capability,並且 CAP_PERFMON 足以為程序提供進行效能監控和可觀察性操作的能力。
授予非特權程序的其他 capability 可以有效地啟用捕獲額外資料,這些資料對於以後對受監控程序或系統的效能分析是必需的。 例如,CAP_SYSLOG capability 允許從 /proc/kallsyms 檔案讀取核心空間記憶體地址。
特權 Perf 使用者組¶
capabilities 機制,特權 capability-dumb 檔案 [6],檔案系統 ACL [10] 和 sudo [15] 實用程式可用於建立專用特權 Perf 使用者組,這些使用者被允許不受限制地執行效能監控和可觀察性。 可以採取以下步驟來建立此類特權 Perf 使用者組。
建立 perf_users 特權 Perf 使用者組,將 perf_users 組分配給 Perf 工具可執行檔案,並限制系統內不在 perf_users 組中的其他使用者對該可執行檔案的訪問
# groupadd perf_users
# ls -alhF
-rwxr-xr-x 2 root root 11M Oct 19 15:12 perf
# chgrp perf_users perf
# ls -alhF
-rwxr-xr-x 2 root perf_users 11M Oct 19 15:12 perf
# chmod o-rwx perf
# ls -alhF
-rwxr-x--- 2 root perf_users 11M Oct 19 15:12 perf
將所需的 capabilities 分配給 Perf 工具可執行檔案,併為 perf_users 組的成員啟用監控和可觀察性特權 [6]
# setcap "cap_perfmon,cap_sys_ptrace,cap_syslog=ep" perf
# setcap -v "cap_perfmon,cap_sys_ptrace,cap_syslog=ep" perf
perf: OK
# getcap perf
perf = cap_sys_ptrace,cap_syslog,cap_perfmon+ep
如果安裝的 libcap [16] 尚不支援 “cap_perfmon”,請改用 “38”,即
# setcap "38,cap_ipc_lock,cap_sys_ptrace,cap_syslog=ep" perf
請注意,您可能需要在混合中使用“cap_ipc_lock”才能使用“perf top”之類的工具,或者使用“perf top -m N”來減少它用於 perf 環形緩衝區的記憶體,請參見下面的記憶體分配部分。
使用不支援 CAP_PERFMON 的 libcap 將導致 cap_get_flag(caps, 38, CAP_EFFECTIVE, &val) 失敗,這將導致預設事件為 ‘cycles:u’,因此,作為一種解決方法,請顯式要求 ‘cycles’ 事件,即
# perf top -e cycles
要使用僅具有 CAP_PERFMON 的 perf 二進位制檔案獲取核心和使用者樣本。
因此,perf_users 組的成員可以透過使用配置的 Perf 工具可執行檔案的功能來進行效能監控和可觀察性,該可執行檔案在執行時會傳遞 perf_events 子系統的範圍檢查。
如果無法為 Perf 工具可執行檔案分配所需的 capabilities(例如,檔案系統以 nosuid 選項掛載或檔案系統不支援擴充套件屬性),則可以建立具有 capabilities 的特權環境,自然是 shell。 該 shell 為固有程序提供 CAP_PERFMON 和其他所需 capabilities,以便在環境中不受限制地進行效能監控和可觀察性操作。 只能透過 sudo 實用程式為 perf_users 組的成員開放對環境的訪問。 為了建立這樣的環境
建立一個 shell 指令碼,該指令碼使用 capsh 實用程式 [16] 將 CAP_PERFMON 和其他所需 capabilities 分配到 shell 程序的環境 capability 集中,在啟用 SECBIT_NO_SETUID_FIXUP,SECBIT_NOROOT 和 SECBIT_NO_CAP_AMBIENT_RAISE 位後鎖定程序安全位,然後將程序身份更改為指令碼的 sudo 呼叫者,該呼叫者本質上應該是 perf_users 組的成員
# ls -alh /usr/local/bin/perf.shell
-rwxr-xr-x. 1 root root 83 Oct 13 23:57 /usr/local/bin/perf.shell
# cat /usr/local/bin/perf.shell
exec /usr/sbin/capsh --iab=^cap_perfmon --secbits=239 --user=$SUDO_USER -- -l
使用 perf_users 組的規則擴充套件 /etc/sudoers 檔案中的 sudo 策略
# grep perf_users /etc/sudoers
%perf_users ALL=/usr/local/bin/perf.shell
檢查 perf_users 組的成員是否有權訪問特權 shell,並且在固有程序的允許,有效和環境 capability 集中啟用了 CAP_PERFMON 和其他所需 capabilities
$ id
uid=1003(capsh_test) gid=1004(capsh_test) groups=1004(capsh_test),1000(perf_users) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
$ sudo perf.shell
[sudo] password for capsh_test:
$ grep Cap /proc/self/status
CapInh: 0000004000000000
CapPrm: 0000004000000000
CapEff: 0000004000000000
CapBnd: 000000ffffffffff
CapAmb: 0000004000000000
$ capsh --decode=0000004000000000
0x0000004000000000=cap_perfmon
因此,perf_users 組的成員可以訪問特權環境,在該環境中,他們可以使用由 CAP_PERFMON Linux capability 管理的效能監控 API 的工具。
此特定訪問控制管理僅適用於執行具有 CAP_SETPCAP, CAP_SETFCAP [6] capabilities 的超級使用者或 root 程序。
非特權使用者¶
非特權程序的 perf_events 範圍和訪問控制由 perf_event_paranoid [2] 設定管理
- -1:
對使用 perf_events 效能監控沒有任何範圍和訪問限制。 在為儲存效能資料分配記憶體緩衝區時,會忽略每個使用者每個 CPU 的 perf_event_mlock_kb [2] 鎖定限制。 這是最不安全的模式,因為允許監控的範圍已最大化,並且沒有對為效能監控分配的資源施加 perf_events 特定限制。
- >=0:
範圍包括每個程序和系統範圍的效能監控,但不包括原始跟蹤點和 ftrace 函式跟蹤點監控。 當在使用者或核心空間中執行時發生的 CPU 和系統事件可以被監控和捕獲以供以後分析。 施加每個使用者每個 CPU 的 perf_event_mlock_kb 鎖定限制,但對於具有 CAP_IPC_LOCK [6] capability 的非特權程序,則忽略該限制。
- >=1:
範圍僅包括每個程序的效能監控,而不包括系統範圍的效能監控。 當在使用者或核心空間中執行時發生的 CPU 和系統事件可以被監控和捕獲以供以後分析。 施加每個使用者每個 CPU 的 perf_event_mlock_kb 鎖定限制,但對於具有 CAP_IPC_LOCK capability 的非特權程序,則忽略該限制。
- >=2:
範圍僅包括每個程序的效能監控。 只能監控和捕獲在使用者空間中執行時發生的 CPU 和系統事件。 施加每個使用者每個 CPU 的 perf_event_mlock_kb 鎖定限制,但對於具有 CAP_IPC_LOCK capability 的非特權程序,則忽略該限制。
資源控制¶
開啟檔案描述符¶
perf_events 系統呼叫 API [2] 為每個配置的 PMU 事件分配檔案描述符。 開啟的檔案描述符是每個程序可計費的資源,由 RLIMIT_NOFILE [11] 限制 (ulimit -n) 管理,該限制通常源自登入 shell 程序。 在為大型伺服器系統上的一長串事件配置 Perf 收集時,很容易達到此限制,從而阻止所需的監控配置。 可以透過修改 limits.conf 檔案 [12] 的內容來增加每個使用者的 RLIMIT_NOFILE 限制。 通常,Perf 取樣會話 (perf record) 需要的開啟 perf_event 檔案描述符的數量不少於受監控事件的數量乘以受監控 CPU 的數量。
記憶體分配¶
使用者程序可用於捕獲效能監控資料的記憶體量由 perf_event_mlock_kb [2] 設定管理。 此 perf_event 特定資源設定定義了允許使用者程序對映以執行效能監控的記憶體的整體每個 CPU 限制。 該設定本質上擴充套件了 RLIMIT_MEMLOCK [11] 限制,但僅適用於專門為捕獲受監控效能事件和相關資料而對映的記憶體區域。
例如,如果一臺機器有八個核心,並且 perf_event_mlock_kb 限制設定為 516 KiB,則為使用者程序提供 516 KiB * 8 = 4128 KiB 的記憶體,該記憶體高於用於 perf_event mmap 緩衝區的 RLIMIT_MEMLOCK 限制 (ulimit -l)。 特別是,這意味著,如果使用者想要啟動兩個或多個性能監控程序,則使用者需要手動將可用的 4128 KiB 分配給監控程序,例如,使用 --mmap-pages Perf 記錄模式選項。 否則,第一個啟動的效能監控程序將分配所有可用的 4128 KiB,而其他程序將由於缺少記憶體而無法繼續。
對於具有 CAP_IPC_LOCK capability 的程序,將忽略 RLIMIT_MEMLOCK 和 perf_event_mlock_kb 資源約束。 因此,可以透過為 Perf 可執行檔案提供 CAP_IPC_LOCK capability,為 perf_events/Perf 特權使用者提供高於 perf_events/Perf 效能監控目的約束的記憶體。