APPLIED[Q/N/J + P/Cmnt]: [SRU][J/N/P/Q/Unstable][PATCH 0/1] CAP_PERFMON insufficient to get perf data
Stefan Bader
stefan.bader at canonical.com
Thu Nov 13 14:07:04 UTC 2025
On 11/11/2025 16:34, Massimiliano Pellizzer wrote:
> BugLink: https://bugs.launchpad.net/bugs/2131046
>
> [ 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.
>
> Massimiliano Pellizzer (1):
> UBUNTU: SAUCE: perf/core: Allow CAP_PERFMON for paranoid level 4
>
> kernel/events/core.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Note that plucky might not release as there is no SRU cycle left before
it has EOL.
Applied to questing,plucky,noble,jammy:linux/master-next. Thanks.
-Stefan
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_0xE8675DEECBEECEA3.asc
Type: application/pgp-keys
Size: 48643 bytes
Desc: OpenPGP public key
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20251113/30228e34/attachment-0001.key>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.ubuntu.com/archives/kernel-team/attachments/20251113/30228e34/attachment-0001.sig>
More information about the kernel-team
mailing list