perf cap: Tidy up and improve capability testing
Remove dependence on libcap. libcap is only used to query whether a capability is supported, which is just 1 capget system call. If the capget system call fails, fall back on root permission checking. Previously if libcap fails then the permission is assumed not present which may be pessimistic/wrong. Add a used_root out argument to perf_cap__capable to say whether the fall back root check was used. This allows the correct error message, "root" vs "users with the CAP_PERFMON or CAP_SYS_ADMIN capability", to be selected. Tidy uses of perf_cap__capable so that tests aren't repeated if capget isn't supported. Signed-off-by: Ian Rogers <irogers@google.com> Cc: Adrian Hunter <adrian.hunter@intel.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Athira Rajeev <atrajeev@linux.vnet.ibm.com> Cc: Changbin Du <changbin.du@huawei.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: James Clark <james.clark@arm.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Kan Liang <kan.liang@linux.intel.com> Cc: Leo Yan <leo.yan@linux.dev> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Oliver Upton <oliver.upton@linux.dev> Cc: Peter Zijlstra <peterz@infradead.org> Link: https://lore.kernel.org/r/20240806220614.831914-1-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
8b1042c425
commit
e25ebda78e
@ -1031,17 +1031,6 @@ ifndef NO_LIBZSTD
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_LIBCAP
|
||||
ifeq ($(feature-libcap), 1)
|
||||
CFLAGS += -DHAVE_LIBCAP_SUPPORT
|
||||
EXTLIBS += -lcap
|
||||
$(call detected,CONFIG_LIBCAP)
|
||||
else
|
||||
$(warning No libcap found, disables capability support, please install libcap-devel/libcap-dev)
|
||||
NO_LIBCAP := 1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifndef NO_BACKTRACE
|
||||
ifeq ($(feature-backtrace), 1)
|
||||
CFLAGS += -DHAVE_BACKTRACE_SUPPORT
|
||||
|
@ -63,20 +63,21 @@ static void ftrace__workload_exec_failed_signal(int signo __maybe_unused,
|
||||
done = true;
|
||||
}
|
||||
|
||||
static int check_ftrace_capable(void)
|
||||
static bool check_ftrace_capable(void)
|
||||
{
|
||||
if (!(perf_cap__capable(CAP_PERFMON) ||
|
||||
perf_cap__capable(CAP_SYS_ADMIN))) {
|
||||
pr_err("ftrace only works for %s!\n",
|
||||
#ifdef HAVE_LIBCAP_SUPPORT
|
||||
"users with the CAP_PERFMON or CAP_SYS_ADMIN capability"
|
||||
#else
|
||||
"root"
|
||||
#endif
|
||||
bool used_root;
|
||||
|
||||
if (perf_cap__capable(CAP_PERFMON, &used_root))
|
||||
return true;
|
||||
|
||||
if (!used_root && perf_cap__capable(CAP_SYS_ADMIN, &used_root))
|
||||
return true;
|
||||
|
||||
pr_err("ftrace only works for %s!\n",
|
||||
used_root ? "root"
|
||||
: "users with the CAP_PERFMON or CAP_SYS_ADMIN capability"
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
static int __write_tracing_file(const char *name, const char *val, bool append)
|
||||
@ -1579,8 +1580,7 @@ int cmd_ftrace(int argc, const char **argv)
|
||||
signal(SIGCHLD, sig_handler);
|
||||
signal(SIGPIPE, sig_handler);
|
||||
|
||||
ret = check_ftrace_capable();
|
||||
if (ret < 0)
|
||||
if (!check_ftrace_capable())
|
||||
return -1;
|
||||
|
||||
ret = perf_config(perf_ftrace_config, &ftrace);
|
||||
|
@ -223,7 +223,7 @@ perf-util-$(CONFIG_ZLIB) += zlib.o
|
||||
perf-util-$(CONFIG_LZMA) += lzma.o
|
||||
perf-util-$(CONFIG_ZSTD) += zstd.o
|
||||
|
||||
perf-util-$(CONFIG_LIBCAP) += cap.o
|
||||
perf-util-y += cap.o
|
||||
|
||||
perf-util-$(CONFIG_CXX_DEMANGLE) += demangle-cxx.o
|
||||
perf-util-y += demangle-ocaml.o
|
||||
|
@ -3,27 +3,52 @@
|
||||
* Capability utilities
|
||||
*/
|
||||
|
||||
#ifdef HAVE_LIBCAP_SUPPORT
|
||||
|
||||
#include "cap.h"
|
||||
#include <stdbool.h>
|
||||
#include <sys/capability.h>
|
||||
#include "debug.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/capability.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
bool perf_cap__capable(cap_value_t cap)
|
||||
#ifndef SYS_capget
|
||||
#define SYS_capget 90
|
||||
#endif
|
||||
|
||||
#define MAX_LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3
|
||||
|
||||
bool perf_cap__capable(int cap, bool *used_root)
|
||||
{
|
||||
cap_flag_value_t val;
|
||||
cap_t caps = cap_get_proc();
|
||||
struct __user_cap_header_struct header = {
|
||||
.version = _LINUX_CAPABILITY_VERSION_3,
|
||||
.pid = getpid(),
|
||||
};
|
||||
struct __user_cap_data_struct data[MAX_LINUX_CAPABILITY_U32S];
|
||||
__u32 cap_val;
|
||||
|
||||
if (!caps)
|
||||
return false;
|
||||
*used_root = false;
|
||||
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;
|
||||
|
||||
if (cap_get_flag(caps, cap, CAP_EFFECTIVE, &val) != 0)
|
||||
val = CAP_CLEAR;
|
||||
pr_debug2("capget syscall failed (%s - %d) fall back on root check\n",
|
||||
strerror(errno), errno);
|
||||
*used_root = true;
|
||||
return geteuid() == 0;
|
||||
}
|
||||
|
||||
if (cap_free(caps) != 0)
|
||||
return false;
|
||||
|
||||
return val == CAP_SET;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBCAP_SUPPORT */
|
||||
|
@ -3,26 +3,6 @@
|
||||
#define __PERF_CAP_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/compiler.h>
|
||||
|
||||
#ifdef HAVE_LIBCAP_SUPPORT
|
||||
|
||||
#include <sys/capability.h>
|
||||
|
||||
bool perf_cap__capable(cap_value_t cap);
|
||||
|
||||
#else
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
static inline bool perf_cap__capable(int cap __maybe_unused)
|
||||
{
|
||||
return geteuid() == 0;
|
||||
}
|
||||
|
||||
#endif /* HAVE_LIBCAP_SUPPORT */
|
||||
|
||||
/* For older systems */
|
||||
#ifndef CAP_SYSLOG
|
||||
@ -33,4 +13,7 @@ static inline bool perf_cap__capable(int cap __maybe_unused)
|
||||
#define CAP_PERFMON 38
|
||||
#endif
|
||||
|
||||
/* Query if a capability is supported, used_root is set if the fallback root check was used. */
|
||||
bool perf_cap__capable(int cap, bool *used_root);
|
||||
|
||||
#endif /* __PERF_CAP_H */
|
||||
|
@ -2425,14 +2425,14 @@ static bool symbol__read_kptr_restrict(void)
|
||||
{
|
||||
bool value = false;
|
||||
FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r");
|
||||
bool used_root;
|
||||
bool cap_syslog = perf_cap__capable(CAP_SYSLOG, &used_root);
|
||||
|
||||
if (fp != NULL) {
|
||||
char line[8];
|
||||
|
||||
if (fgets(line, sizeof(line), fp) != NULL)
|
||||
value = perf_cap__capable(CAP_SYSLOG) ?
|
||||
(atoi(line) >= 2) :
|
||||
(atoi(line) != 0);
|
||||
value = cap_syslog ? (atoi(line) >= 2) : (atoi(line) != 0);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
@ -2440,7 +2440,7 @@ static bool symbol__read_kptr_restrict(void)
|
||||
/* Per kernel/kallsyms.c:
|
||||
* we also restrict when perf_event_paranoid > 1 w/o CAP_SYSLOG
|
||||
*/
|
||||
if (perf_event_paranoid() > 1 && !perf_cap__capable(CAP_SYSLOG))
|
||||
if (perf_event_paranoid() > 1 && !cap_syslog)
|
||||
value = true;
|
||||
|
||||
return value;
|
||||
|
@ -325,9 +325,15 @@ int perf_event_paranoid(void)
|
||||
|
||||
bool perf_event_paranoid_check(int max_level)
|
||||
{
|
||||
return perf_cap__capable(CAP_SYS_ADMIN) ||
|
||||
perf_cap__capable(CAP_PERFMON) ||
|
||||
perf_event_paranoid() <= max_level;
|
||||
bool used_root;
|
||||
|
||||
if (perf_cap__capable(CAP_SYS_ADMIN, &used_root))
|
||||
return true;
|
||||
|
||||
if (!used_root && perf_cap__capable(CAP_PERFMON, &used_root))
|
||||
return true;
|
||||
|
||||
return perf_event_paranoid() <= max_level;
|
||||
}
|
||||
|
||||
static int
|
||||
|
Loading…
Reference in New Issue
Block a user