| // SPDX-License-Identifier: GPL-2.0 | |
| /* | |
| * Capability utilities | |
| */ | |
| #include "cap.h" | |
| #include "debug.h" | |
| #include <errno.h> | |
| #include <string.h> | |
| #include <sys/syscall.h> | |
| #include <unistd.h> | |
| #define MAX_LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3 | |
| bool perf_cap__capable(int cap) | |
| { | |
| struct __user_cap_header_struct header = { | |
| .version = _LINUX_CAPABILITY_VERSION_3, | |
| .pid = 0, | |
| }; | |
| struct __user_cap_data_struct data[MAX_LINUX_CAPABILITY_U32S] = {}; | |
| __u32 cap_val; | |
| while (syscall(SYS_capget, &header, &data[0]) == -1) { | |
| /* Retry, first attempt has set the header.version correctly. */ | |
| if (errno == EINVAL && header.version != _LINUX_CAPABILITY_VERSION_3 && | |
| header.version == _LINUX_CAPABILITY_VERSION_1) | |
| continue; | |
| pr_debug2("capget syscall failed (%m) fall back on root check\n"); | |
| return geteuid() == 0; | |
| } | |
| /* Extract the relevant capability bit. */ | |
| if (cap >= 32) { | |
| if (header.version == _LINUX_CAPABILITY_VERSION_3) { | |
| cap_val = data[1].effective; | |
| } else { | |
| /* Capability beyond 32 is requested but only 32 are supported. */ | |
| return false; | |
| } | |
| } else { | |
| cap_val = data[0].effective; | |
| } | |
| return (cap_val & (1 << (cap & 0x1f))) != 0; | |
| } |