Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf tools: Add helpers to use capabilities if present

Add utilities to help checking capabilities of the running procss. Make
perf link with libcap, if it is available. If no libcap-dev[el],
fallback to the geteuid() == 0 test used before.

Committer notes:

$ perf test python
18: 'import perf' in python : FAILED!
$ perf test -v python
Couldn't bump rlimit(MEMLOCK), failures may take place when creating BPF maps, etc
18: 'import perf' in python :
--- start ---
test child forked, pid 23288
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: /tmp/build/perf/python/perf.so: undefined symbol: cap_get_flag
test child finished with -1
---- end ----
'import perf' in python: FAILED!
$

This happens because differently from the perf binary generated with
this patch applied:

$ ldd /tmp/build/perf/perf | grep libcap
libcap.so.2 => /lib64/libcap.so.2 (0x00007f724a4ef000)
$

The python binding isn't linking with libcap:

$ ldd /tmp/build/perf/python/perf.so | grep libcap
$

So add 'cap' to the 'extra_libraries' variable in
tools/perf/util/setup.py, and rebuild:

$ perf test python
18: 'import perf' in python : Ok
$

If we explicitely disable libcap it also continues to work:

$ make NO_LIBCAP=1 -C tools/perf O=/tmp/build/perf install-bin
$ ldd /tmp/build/perf/perf | grep libcap
$ ldd /tmp/build/perf/python/perf.so | grep libcap
$ perf test python
18: 'import perf' in python : Ok
$

Signed-off-by: Igor Lubashev <ilubashe@akamai.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexey Budankov <alexey.budankov@linux.intel.com>
Cc: James Morris <jmorris@namei.org>
Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Suzuki Poulouse <suzuki.poulose@arm.com>
Cc: linux-arm-kernel@lists.infradead.org
[ split from a larger patch ]
Link: http://lkml.kernel.org/r/8a1e76cf5c7c9796d0d4d240fbaa85305298aafa.1565188228.git.ilubashe@akamai.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Igor Lubashev and committed by
Arnaldo Carvalho de Melo
c22e150e 74d5f3d0

+71
+2
tools/perf/util/Build
··· 148 148 perf-$(CONFIG_LZMA) += lzma.o 149 149 perf-$(CONFIG_ZSTD) += zstd.o 150 150 151 + perf-$(CONFIG_LIBCAP) += cap.o 152 + 151 153 perf-y += demangle-java.o 152 154 perf-y += demangle-rust.o 153 155
+29
tools/perf/util/cap.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Capability utilities 4 + */ 5 + 6 + #ifdef HAVE_LIBCAP_SUPPORT 7 + 8 + #include "cap.h" 9 + #include <stdbool.h> 10 + #include <sys/capability.h> 11 + 12 + bool perf_cap__capable(cap_value_t cap) 13 + { 14 + cap_flag_value_t val; 15 + cap_t caps = cap_get_proc(); 16 + 17 + if (!caps) 18 + return false; 19 + 20 + if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val) != 0) 21 + val = CAP_CLEAR; 22 + 23 + if (cap_free(caps) != 0) 24 + return false; 25 + 26 + return val == CAP_SET; 27 + } 28 + 29 + #endif /* HAVE_LIBCAP_SUPPORT */
+27
tools/perf/util/cap.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __PERF_CAP_H 3 + #define __PERF_CAP_H 4 + 5 + #include <stdbool.h> 6 + #include <linux/capability.h> 7 + #include <linux/compiler.h> 8 + 9 + #ifdef HAVE_LIBCAP_SUPPORT 10 + 11 + #include <sys/capability.h> 12 + 13 + bool perf_cap__capable(cap_value_t cap); 14 + 15 + #else 16 + 17 + #include <unistd.h> 18 + #include <sys/types.h> 19 + 20 + static inline bool perf_cap__capable(int cap __maybe_unused) 21 + { 22 + return geteuid() == 0; 23 + } 24 + 25 + #endif /* HAVE_LIBCAP_SUPPORT */ 26 + 27 + #endif /* __PERF_CAP_H */
+1
tools/perf/util/event.h
··· 851 851 void event_attr_init(struct perf_event_attr *attr); 852 852 853 853 int perf_event_paranoid(void); 854 + bool perf_event_paranoid_check(int max_level); 854 855 855 856 extern int sysctl_perf_event_max_stack; 856 857 extern int sysctl_perf_event_max_contexts_per_stack;
+1
tools/perf/util/python-ext-sources
··· 7 7 8 8 util/python.c 9 9 ../lib/ctype.c 10 + util/cap.c 10 11 util/evlist.c 11 12 util/evsel.c 12 13 util/cpumap.c
+2
tools/perf/util/setup.py
··· 59 59 extra_libraries = [] 60 60 if '-DHAVE_LIBNUMA_SUPPORT' in cflags: 61 61 extra_libraries = [ 'numa' ] 62 + if '-DHAVE_LIBCAP_SUPPORT' in cflags: 63 + extra_libraries += [ 'cap' ] 62 64 63 65 perf = Extension('perf', 64 66 sources = ext_sources,
+9
tools/perf/util/util.c
··· 16 16 #include <string.h> 17 17 #include <errno.h> 18 18 #include <limits.h> 19 + #include <linux/capability.h> 19 20 #include <linux/kernel.h> 20 21 #include <linux/log2.h> 21 22 #include <linux/time64.h> 22 23 #include <unistd.h> 24 + #include "cap.h" 23 25 #include "strlist.h" 24 26 #include "string2.h" 25 27 ··· 405 403 406 404 return value; 407 405 } 406 + 407 + bool perf_event_paranoid_check(int max_level) 408 + { 409 + return perf_cap__capable(CAP_SYS_ADMIN) || 410 + perf_event_paranoid() <= max_level; 411 + } 412 + 408 413 static int 409 414 fetch_ubuntu_kernel_version(unsigned int *puint) 410 415 {