1c22e150eSIgor Lubashev // SPDX-License-Identifier: GPL-2.0 2c22e150eSIgor Lubashev /* 3c22e150eSIgor Lubashev * Capability utilities 4c22e150eSIgor Lubashev */ 5c22e150eSIgor Lubashev 6c22e150eSIgor Lubashev #include "cap.h" 7*e25ebda7SIan Rogers #include "debug.h" 8*e25ebda7SIan Rogers #include <errno.h> 9*e25ebda7SIan Rogers #include <string.h> 10*e25ebda7SIan Rogers #include <unistd.h> 11*e25ebda7SIan Rogers #include <linux/capability.h> 12*e25ebda7SIan Rogers #include <sys/syscall.h> 13c22e150eSIgor Lubashev 14*e25ebda7SIan Rogers #ifndef SYS_capget 15*e25ebda7SIan Rogers #define SYS_capget 90 16*e25ebda7SIan Rogers #endif 17*e25ebda7SIan Rogers 18*e25ebda7SIan Rogers #define MAX_LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3 19*e25ebda7SIan Rogers 20*e25ebda7SIan Rogers bool perf_cap__capable(int cap, bool *used_root) 21c22e150eSIgor Lubashev { 22*e25ebda7SIan Rogers struct __user_cap_header_struct header = { 23*e25ebda7SIan Rogers .version = _LINUX_CAPABILITY_VERSION_3, 24*e25ebda7SIan Rogers .pid = getpid(), 25*e25ebda7SIan Rogers }; 26*e25ebda7SIan Rogers struct __user_cap_data_struct data[MAX_LINUX_CAPABILITY_U32S]; 27*e25ebda7SIan Rogers __u32 cap_val; 28c22e150eSIgor Lubashev 29*e25ebda7SIan Rogers *used_root = false; 30*e25ebda7SIan Rogers while (syscall(SYS_capget, &header, &data[0]) == -1) { 31*e25ebda7SIan Rogers /* Retry, first attempt has set the header.version correctly. */ 32*e25ebda7SIan Rogers if (errno == EINVAL && header.version != _LINUX_CAPABILITY_VERSION_3 && 33*e25ebda7SIan Rogers header.version == _LINUX_CAPABILITY_VERSION_1) 34*e25ebda7SIan Rogers continue; 35c22e150eSIgor Lubashev 36*e25ebda7SIan Rogers pr_debug2("capget syscall failed (%s - %d) fall back on root check\n", 37*e25ebda7SIan Rogers strerror(errno), errno); 38*e25ebda7SIan Rogers *used_root = true; 39*e25ebda7SIan Rogers return geteuid() == 0; 40c22e150eSIgor Lubashev } 41c22e150eSIgor Lubashev 42*e25ebda7SIan Rogers /* Extract the relevant capability bit. */ 43*e25ebda7SIan Rogers if (cap >= 32) { 44*e25ebda7SIan Rogers if (header.version == _LINUX_CAPABILITY_VERSION_3) { 45*e25ebda7SIan Rogers cap_val = data[1].effective; 46*e25ebda7SIan Rogers } else { 47*e25ebda7SIan Rogers /* Capability beyond 32 is requested but only 32 are supported. */ 48*e25ebda7SIan Rogers return false; 49*e25ebda7SIan Rogers } 50*e25ebda7SIan Rogers } else { 51*e25ebda7SIan Rogers cap_val = data[0].effective; 52*e25ebda7SIan Rogers } 53*e25ebda7SIan Rogers return (cap_val & (1 << (cap & 0x1f))) != 0; 54*e25ebda7SIan Rogers } 55