|
13 | 13 | #include <stdio.h>
|
14 | 14 | #include <stdlib.h>
|
15 | 15 | #include <string.h>
|
| 16 | +#include <sys/capability.h> |
16 | 17 | #include <sys/epoll.h>
|
17 | 18 | #include <sys/stat.h>
|
18 | 19 | #include <sys/types.h>
|
@@ -713,3 +714,49 @@ bool can_access_personality(void)
|
713 | 714 |
|
714 | 715 | return could_access_init_personality != 0;
|
715 | 716 | }
|
| 717 | + |
| 718 | +/* inspired by the Linux kernel's selftests/bpf :-) */ |
| 719 | +bool proc_has_capability(pid_t pid, __u64 caps) |
| 720 | +{ |
| 721 | + struct __user_cap_data_struct data[_LINUX_CAPABILITY_U32S_3]; |
| 722 | + struct __user_cap_header_struct hdr = { |
| 723 | + .version = _LINUX_CAPABILITY_VERSION_3, |
| 724 | + }; |
| 725 | + __u32 cap0 = caps; |
| 726 | + __u32 cap1 = caps >> 32; |
| 727 | + int err; |
| 728 | + |
| 729 | + err = capget(&hdr, data); |
| 730 | + if (err) |
| 731 | + return false; |
| 732 | + |
| 733 | + return ((data[0].effective & cap0) == cap0 && |
| 734 | + (data[1].effective & cap1) == cap1); |
| 735 | +} |
| 736 | + |
| 737 | +#define LXCFS_PROC_USER_NS_LEN \ |
| 738 | + (STRLITERALLEN("/proc/") + INTTYPE_TO_STRLEN(uint64_t) + \ |
| 739 | + STRLITERALLEN("/ns/user") + 1) |
| 740 | + |
| 741 | +static ino_t get_userns_ino(pid_t pid) |
| 742 | +{ |
| 743 | + char path[LXCFS_PROC_USER_NS_LEN]; |
| 744 | + struct stat st; |
| 745 | + |
| 746 | + snprintf(path, sizeof(path), "/proc/%d/ns/user", pid); |
| 747 | + if (stat(path, &st)) |
| 748 | + return 0; |
| 749 | + |
| 750 | + return st.st_ino; |
| 751 | +} |
| 752 | + |
| 753 | +bool proc_has_capability_in(pid_t nspid, pid_t pid, cap_value_t cap) |
| 754 | +{ |
| 755 | + ino_t nspid_userns_ino, pid_userns_ino; |
| 756 | + |
| 757 | + nspid_userns_ino = get_userns_ino(nspid); |
| 758 | + pid_userns_ino = get_userns_ino(pid); |
| 759 | + |
| 760 | + return (nspid_userns_ino == pid_userns_ino) && |
| 761 | + proc_has_capability(pid, 1ULL << cap); |
| 762 | +} |
0 commit comments