** Description changed:
+ [ Impact ]
+
+ The Ubuntu-specific perf_event_paranoid level 4 introduces an additional
+ capability check that requires CAP_SYS_ADMIN to access perf events.
+ However, this check was implemented before CAP_PERFMON was introduced,
+ and was never updated to recognize the new capability.
+
+ CAP_PERFMON was specifically designed to allow performance monitoring
+ operations without granting the broad privileges of CAP_SYS_ADMIN. The
+ current implementation forces users to grant CAP_SYS_ADMIN even when
+ CAP_PERFMON would be sufficient, violating the principle of least
+ privilege.
+
+ The perfmon_capable() helper function checks for either CAP_PERFMON or
+ CAP_SYS_ADMIN, providing the intended functionality while maintaining
+ backward compatibility with systems that use CAP_SYS_ADMIN.
+
+ This change allows processes with CAP_PERFMON to access perf events when
+ perf_event_paranoid is set to 4, while still requiring explicit grants
+ as intended by the stricter paranoid level. Processes with CAP_SYS_ADMIN
+ continue to work as before.
+
+ [ Test Plan ]
+
+ Use the following reproducer (with CAP_PERFMON file capabilities) to check
+ if CAP_SYS_ADMIN is still required.
+
+ ```
+ #include <stdio.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <sys/capability.h>
+ #include <sys/syscall.h>
+ #include <sys/types.h>
+ #include <linux/perf_event.h>
+
+ static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid, int
cpu, int group_fd, unsigned long flags) {
+ return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
+ }
+
+ void print_capabilities(void) {
+ cap_t capabilities;
+ char *capabilities_text;
+
+ capabilities = cap_get_proc();
+ if (capabilities == NULL) {
+ printf("[!] Impossbile to get process capabilities.\n");
+ return;
+ }
+
+ capabilities_text = cap_to_text(capabilities, NULL);
+ if (capabilities_text == NULL) {
+ printf("[!] Impossbile to convert process capabilities.\n");
+ cap_free(capabilities);
+ return;
+ }
+
+ printf("[*] Current capabilities: %s\n", capabilities_text);
+
+ cap_free(capabilities_text);
+ cap_free(capabilities);
+ }
+
+ int check_perf_access(const char *event_name, int event_type, int
event_config) {
+ struct perf_event_attr pe;
+ int fd;
+
+ memset(&pe, 0, sizeof(struct perf_event_attr));
+ pe.type = event_type;
+ pe.size = sizeof(struct perf_event_attr);
+ pe.config = event_config;
+ pe.disabled = 1;
+ pe.exclude_kernel = 0;
+ pe.exclude_hv = 1;
+
+ fd = perf_event_open(&pe, 0, -1, -1, 0);
+
+ if (fd == -1) {
+ printf("[!] %s: Impossible to open perf event\n", event_name);
+ return -1;
+ } else {
+ printf("[*] %s: Successfully opened perf event\n", event_name);
+ close(fd);
+ return 0;
+ }
+ }
+
+ int main(int argc, char *argv[]) {
+ int result = 0;
+ FILE *fp;
+ int paranoid_level = -2;
+
+ fp = fopen("/proc/sys/kernel/perf_event_paranoid", "r");
+ if (fp) {
+ if (fscanf(fp, "%d", ¶noid_level) == 1) {
+ printf("[*] Current perf_event_paranoid level: %d.\n", paranoid_level);
+ if (paranoid_level == 4) {
+ printf("[*] This is a custom Ubuntu paranoid level.\n");
+ }
+ }
+ fclose(fp);
+ } else {
+ printf("[!] Impossible to perf_event_paranoid level.\n");
+ }
+
+ printf("\n");
+
+ print_capabilities();
+
+ printf("\n");
+
+ result += check_perf_access("CPU_CYCLES", PERF_TYPE_HARDWARE,
PERF_COUNT_HW_CPU_CYCLES);
+ result += check_perf_access("INSTRUCTIONS", PERF_TYPE_HARDWARE,
PERF_COUNT_HW_INSTRUCTIONS);
+ result += check_perf_access("CACHE_REFERENCES", PERF_TYPE_HARDWARE,
PERF_COUNT_HW_CACHE_REFERENCES);
+
+ printf("\n");
+
+ if (result == 0) {
+ printf("All perf events accessible with current capabilities\n");
+ } else {
+ printf("Some events were not accessible with current capabilities\n");
+ }
+ }
+ ```
+
+ Before the patch:
+
+ ```
+ $ ./perf_repro
+ [*] Current perf_event_paranoid level: 4.
+ [*] This is a custom Ubuntu paranoid level.
+
+ [*] Current capabilities: cap_perfmon=ep
+
+ [!] CPU_CYCLES: Impossible to open perf event
+ [!] INSTRUCTIONS: Impossible to open perf event
+ [!] CACHE_REFERENCES: Impossible to open perf event
+
+ Some events were not accessible with current capabilities
+ ```
+
+ After the patch:
+ ```
+ $ ./perf_repro
+ [*] Current perf_event_paranoid level: 4.
+ [*] This is a custom Ubuntu paranoid level.
+
+ [*] Current capabilities: cap_perfmon=ep
+
+ [*] CPU_CYCLES: Successfully opened perf event
+ [*] INSTRUCTIONS: Successfully opened perf event
+ [*] CACHE_REFERENCES: Successfully opened perf event
+
+ All perf events accessible with current capabilities
+ ```
+
+ [ Regression Potential ]
+
+ The regression potential is minimal.
+ The fix maintains backward compatibility as perfmon_capable() accepts both
+ CAP_SYS_ADMIN and CAP_PERFMON, ensuring all curently working systems are not
impacted by the fix.
+ No security weakening occurs since CAP_PERFMON was designed for performance
monitoring and provides fewer privileges than CAP_SYS_ADMIN.
+
+ ---
+
I am trying to run node_exporter without root, with cap_perfmon and
--collector.perf as well as
--collector.perf.hardware-profilers=CpuCycles,CpuInstr.
Expected behavior: node_exporter exports instructions and cpu cycle metrics
Actual behavior: no perf metrics
version: Ubuntu 6.8.0-87.88-generic 6.8.12
Ubuntu carries a patch that introduces a new security level for perf events:
perf_event_paranoid=4
This patch limits calling the perf open syscall to processes with
CAP_SYS_ADMIN. This patch is from ~2016.
Example commit for resolute: https://git.launchpad.net/~canonical-
kernel/ubuntu/+source/linux-
aws/+git/resolute/commit/kernel/events/core.c?id=eaa91347f6f8112c5c567f93123bfe3b82bd1593
In 2020 a new capability was introduced, CAP_PERFMON, that should be
sufficient for using perf.
The code now checks with perfmon_capable() if the process has CAP_SYS_ADMIN
_or_ CAP_PERFMON. I am trying to get cpu hardware metrics with CAP_PERFMON but
can't.
Looking at the commit message, timing and effect I think the introduction of
CAP_PERFMON was missed
The patch
> + if (perf_paranoid_any() && !capable(CAP_SYS_ADMIN))
> + return -EACCES;
should probably be
> + if (perf_paranoid_any() && !perfmon_capable())
> + return -EACCES;
ProblemType: Bug
DistroRelease: Ubuntu 24.04
Package: linux-image-6.8.0-87-generic 6.8.0-87.88
ProcVersionSignature: Ubuntu 6.8.0-87.88-generic 6.8.12
Uname: Linux 6.8.0-87-generic x86_64
ApportVersion: 2.28.1-0ubuntu3.8
Architecture: amd64
AudioDevicesInUse:
- USER PID ACCESS COMMAND
- /dev/snd/controlC0: rtreffer 2521 F.... wireplumber
- /dev/snd/seq: rtreffer 2519 F.... pipewire
+ USER PID ACCESS COMMAND
+ /dev/snd/controlC0: rtreffer 2521 F.... wireplumber
+ /dev/snd/seq: rtreffer 2519 F.... pipewire
CRDA: N/A
CasperMD5CheckResult: pass
Date: Mon Nov 10 21:46:59 2025
InstallationDate: Installed on 2025-11-08 (2 days ago)
InstallationMedia: Ubuntu-Server 24.04.3 LTS "Noble Numbat" - Release amd64
(20250805.1)
IwConfig:
- lo no wireless extensions.
-
- enp1s0 no wireless extensions.
+ lo no wireless extensions.
+
+ enp1s0 no wireless extensions.
Lsusb:
- Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
- Bus 001 Device 002: ID 08e6:4433 Gemalto (was Gemplus) GemPC433-Swap
- Bus 001 Device 003: ID 0627:0001 Adomax Technology Co., Ltd QEMU Tablet
- Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
+ Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
+ Bus 001 Device 002: ID 08e6:4433 Gemalto (was Gemplus) GemPC433-Swap
+ Bus 001 Device 003: ID 0627:0001 Adomax Technology Co., Ltd QEMU Tablet
+ Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Lsusb-t:
- /: Bus 001.Port 001: Dev 001, Class=root_hub, Driver=xhci_hcd/15p, 480M
- |__ Port 001: Dev 002, If 0, Class=Chip/SmartCard, Driver=[none], 12M
- |__ Port 002: Dev 003, If 0, Class=Human Interface Device,
Driver=usbhid, 480M
- /: Bus 002.Port 001: Dev 001, Class=root_hub, Driver=xhci_hcd/15p, 5000M
+ /: Bus 001.Port 001: Dev 001, Class=root_hub, Driver=xhci_hcd/15p, 480M
+ |__ Port 001: Dev 002, If 0, Class=Chip/SmartCard, Driver=[none], 12M
+ |__ Port 002: Dev 003, If 0, Class=Human Interface Device,
Driver=usbhid, 480M
+ /: Bus 002.Port 001: Dev 001, Class=root_hub, Driver=xhci_hcd/15p, 5000M
MachineType: QEMU Standard PC (Q35 + ICH9, 2009)
ProcEnviron:
- LANG=en_US.UTF-8
- PATH=(custom, no user)
- SHELL=/bin/bash
- TERM=xterm-256color
+ LANG=en_US.UTF-8
+ PATH=(custom, no user)
+ SHELL=/bin/bash
+ TERM=xterm-256color
ProcFB: 0 virtio_gpudrmfb
ProcKernelCmdLine: BOOT_IMAGE=/vmlinuz-6.8.0-87-generic
root=/dev/mapper/ubuntu--vg-ubuntu--lv ro
RelatedPackageVersions:
- linux-restricted-modules-6.8.0-87-generic N/A
- linux-backports-modules-6.8.0-87-generic N/A
- linux-firmware 20240318.git3b128b60-0ubuntu2.19
+ linux-restricted-modules-6.8.0-87-generic N/A
+ linux-backports-modules-6.8.0-87-generic N/A
+ linux-firmware 20240318.git3b128b60-0ubuntu2.19
RfKill:
-
+
SourcePackage: linux
UpgradeStatus: No upgrade log present (probably fresh install)
dmi.bios.date: 10/08/2025
dmi.bios.release: 0.0
dmi.bios.vendor: Ubuntu distribution of EDK II
dmi.bios.version: 2025.02-8ubuntu3
dmi.chassis.type: 1
dmi.chassis.vendor: QEMU
dmi.chassis.version: pc-q35-10.1
dmi.modalias:
dmi:bvnUbuntudistributionofEDKII:bvr2025.02-8ubuntu3:bd10/08/2025:br0.0:svnQEMU:pnStandardPC(Q35+ICH9,2009):pvrpc-q35-10.1:cvnQEMU:ct1:cvrpc-q35-10.1:sku:
dmi.product.name: Standard PC (Q35 + ICH9, 2009)
dmi.product.version: pc-q35-10.1
dmi.sys.vendor: QEMU
** Also affects: linux (Ubuntu Resolute)
Importance: Undecided
Assignee: Massimiliano Pellizzer (mpellizzer)
Status: Confirmed
** Also affects: linux (Ubuntu Noble)
Importance: Undecided
Status: New
** Also affects: linux (Ubuntu Jammy)
Importance: Undecided
Status: New
** Also affects: linux (Ubuntu Plucky)
Importance: Undecided
Status: New
** Also affects: linux (Ubuntu Questing)
Importance: Undecided
Status: New
** Changed in: linux (Ubuntu Resolute)
Status: Confirmed => In Progress
** Changed in: linux (Ubuntu Questing)
Status: New => In Progress
** Changed in: linux (Ubuntu Plucky)
Status: New => In Progress
** Changed in: linux (Ubuntu Noble)
Status: New => In Progress
** Changed in: linux (Ubuntu Jammy)
Status: New => In Progress
** Changed in: linux (Ubuntu Jammy)
Assignee: (unassigned) => Massimiliano Pellizzer (mpellizzer)
** Changed in: linux (Ubuntu Noble)
Assignee: (unassigned) => Massimiliano Pellizzer (mpellizzer)
** Changed in: linux (Ubuntu Plucky)
Assignee: (unassigned) => Massimiliano Pellizzer (mpellizzer)
** Changed in: linux (Ubuntu Questing)
Assignee: (unassigned) => Massimiliano Pellizzer (mpellizzer)
--
You received this bug notification because you are a member of Ubuntu
Bugs, which is subscribed to Ubuntu.
https://bugs.launchpad.net/bugs/2131046
Title:
CAP_PERFMON insufficient to get perf data
To manage notifications about this bug go to:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2131046/+subscriptions
--
ubuntu-bugs mailing list
[email protected]
https://lists.ubuntu.com/mailman/listinfo/ubuntu-bugs