Perf 事件和工具安全
概述
使用 Linux 性能计数器 (perf_events) 可能会带来相当大的泄露受监控进程访问的敏感数据的风险。在直接使用 perf_events 系统调用 API 的情况下以及通过 Perf 工具用户模式实用程序 (Perf) 生成的数据文件的情况下,都可能发生数据泄漏。风险取决于 perf_events 性能监控单元 (PMU) 和 Perf 收集和公开用于性能分析的数据的性质。收集的系统和性能数据可以分为几类:
-
系统硬件和软件配置数据,例如:CPU型号及其缓存配置、可用内存量及其拓扑、使用的内核和Perf版本、性能监控设置(包括实验时间、事件配置、Perf命令行参数等)。
-
用户和内核模块路径及其加载地址及其大小、进程和线程名称及其 PID 和 TID、捕获的硬件和软件事件的时间戳。
-
内核软件计数器(例如,上下文切换、页面错误、CPU 迁移)、架构硬件性能计数器 (PMC) 8和机器特定寄存器 (MSR) 9的内容,为系统的各个受监控部分(例如,内存)提供执行度量控制器 (IMC)、互连 (QPI/UPI) 或外设 (PCIe) 非核心计数器),无需直接归因于任何执行上下文状态。
-
架构执行上下文寄存器的内容(例如,x86_64 上的 RIP、RSP、RBP)、进程用户和内核空间内存地址和数据、从该类别捕获数据的各种架构 MSR 的内容。
属于第四类的数据可能包含敏感的过程数据。如果某些监视模式下的 PMU 捕获执行上下文寄存器的值或来自进程存储器的数据,则需要正确排序和保护对此类监视模式的访问。因此,perf_events 性能监控和可观察性操作是安全访问控制管理的主题。
perf_events 访问控制
为了执行安全检查,Linux 实现将进程分为两类6:a) 特权进程(其有效用户 ID 为 0,称为超级用户或 root),b) 非特权进程(其有效 UID 不为零)。特权进程绕过所有内核安全权限检查,因此特权进程完全可以使用 perf_events 性能监控,而无需访问、范围和资源限制。
非特权进程需要根据进程的凭据5(通常:有效 UID、有效 GID 和补充组列表)接受全面的安全权限检查。
Linux 将传统上与超级用户相关的特权划分为不同的单元,称为功能6,可以针对非特权用户的进程和文件在每个线程上独立启用和禁用。
授予非特权进程的其他功能可以有效地捕获后续对受监视进程或系统进行性能分析所需的附加数据。例如,CAP_SYSLOG 功能允许从 /proc/kallsyms 文件读取内核空间内存地址
特权 Perf 用户组
能力机制、特权能力哑文件6、文件系统 ACL 和 sudo 实用程序可用于创建特权 Perf 用户的专用组,这些用户被允许无限制地执行性能监控和可观察性。可以采取以下步骤来创建此类特权 Perf 用户组。
- 创建特权 Perf 用户的 perf_users 组,将 perf_users 组分配给 Perf 工具可执行文件,并限制系统中不属于 perf_users 组的其他用户对可执行文件的访问:
# groupadd perf_users
- 将所需的功能分配给 Perf 工具可执行文件,并为 perf_users 组的成员启用监视和可观察权限:
# setcap "cap_perfmon,cap_sys_ptrace,cap_syslog=ep" perf
# setcap -v "cap_perfmon,cap_sys_ptrace,cap_syslog=ep" perf
perf_users 组的成员能够使用已配置的 Perf 工具可执行文件的功能进行性能监视和可观察性,该可执行文件在执行时会通过 perf_events 子系统范围检查。
因此,perf_users 组的成员可以访问特权环境,在其中他们可以使用采用由 CAP_PERFMON Linux 功能控制的性能监控 API 的工具。
这种特定的访问控制管理仅适用于具有 CAP_SETPCAP、CAP_SETFCAP 功能的超级用户或根运行进程。
非特权用户
非特权进程的 perf_events 范围和访问控制由 perf_event_paranoid 设置控制:
-
-1:
对使用 perf_events 性能监控不施加任何范围和访问限制。 分配内存缓冲区用于存储性能数据时,将忽略每用户每 CPU perf_event_mlock_kb 锁定限制。 这是最不安全的模式,因为允许的监视范围已最大化,并且没有对分配给性能监视的资源施加 perf_events 特定限制。 -
>=0:
范围包括每个进程和系统范围的性能监控,但不包括原始跟踪点和 ftrace 函数跟踪点监控。 可以监视和捕获在用户或内核空间中执行时发生的 CPU 和系统事件以供以后分析。 对于具有 CAP_IPC_LOCK 功能的非特权进程,会施加每用户每 cpu perf_event_mlock_kb 锁定限制,但会忽略该限制。 -
>=1:
范围仅包括每个进程的性能监控,不包括系统范围的性能监控。 可以监视和捕获在用户或内核空间中执行时发生的 CPU 和系统事件以供以后分析。 对于具有 CAP_IPC_LOCK 功能的非特权进程,会施加每用户每 CPU perf_event_mlock_kb 锁定限制,但会忽略该限制。 -
>=2:
范围仅包括每个进程的性能监控。 只有在用户空间执行时发生的 CPU 和系统事件才能被监视和捕获以供以后分析。 对于具有 CAP_IPC_LOCK 功能的非特权进程,会施加每用户每 CPU perf_event_mlock_kb 锁定限制,但会忽略该限制。
资源控制
perf_events 系统调用 API 为每个配置的 PMU 事件分配文件描述符。
打开文件描述符是受 LIMIT_NOFILE 限制 (ulimit -n) 控制的每进程可解释资源,该限制通常源自登录 shell 进程。 在大型服务器系统上为一长串事件配置 Perf 收集时,很容易达到此限制,从而阻止所需的监视配置。
RLIMIT_NOFILE 限制可以在每个用户的基础上修改 limit.conf 文件的内容来增加。 通常,Perf 采样会话(perf 记录)需要打开的 perf_event 文件描述符数量不少于受监控事件数乘以受监控 CPU 数。
内存分配
用户进程可用于捕获性能监控数据的内存量由 perf_event_mlock_kb 设置控制。 此 perf_event 特定资源设置定义了允许用户进程映射以执行性能监控的每 CPU 内存总体限制。 该设置实质上扩展了 RLIMIT_MEMLOCK 限制,但仅适用于专门映射用于捕获受监控性能事件和相关数据的内存区域。
例如,如果计算机有 8 个核心,并且 perf_event_mlock_kb 限制设置为 516 KiB,则为用户进程提供高于 perf_event mmap 缓冲区的 RLIMIT_MEMLOCK 限制 (ulimit -l) 的 516 KiB * 8 = 4128 KiB 内存。 特别是,这意味着,如果用户想要启动两个或多个性能监控进程,则需要用户在监控进程之间手动分配可用的 4128 KiB,例如使用 --mmap-pages Perf 记录模式选项 。 否则,第一个启动的性能监控进程将分配所有可用的 4128 KiB,其他进程将因内存不足而无法继续进行。
对于具有 CAP_IPC_LOCK 功能的进程,将忽略 RLIMIT_MEMLOCK 和 perf_event_mlock_kb 资源约束。 因此,通过为 Perf 可执行文件提供 CAP_IPC_LOCK 功能,可以为 perf_events/Perf 特权用户提供超出 perf_events/Perf 性能监控目的约束的内存。