summaryrefslogtreecommitdiff
path: root/tools/bpf/bpftool/feature.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/bpf/bpftool/feature.c')
-rw-r--r--tools/bpf/bpftool/feature.c102
1 files changed, 89 insertions, 13 deletions
diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c
index 59e4cb44efbc..952f4b1987c0 100644
--- a/tools/bpf/bpftool/feature.c
+++ b/tools/bpf/bpftool/feature.c
@@ -6,6 +6,7 @@
#include <string.h>
#include <unistd.h>
#include <net/if.h>
+#include <sys/capability.h>
#include <sys/utsname.h>
#include <sys/vfs.h>
@@ -36,6 +37,7 @@ static const char * const helper_name[] = {
#undef BPF_HELPER_MAKE_ENTRY
static bool full_mode;
+static bool run_as_unprivileged;
/* Miscellaneous utility functions */
@@ -473,6 +475,11 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types,
}
res = bpf_probe_prog_type(prog_type, ifindex);
+ /* Probe may succeed even if program load fails, for unprivileged users
+ * check that we did not fail because of insufficient permissions
+ */
+ if (run_as_unprivileged && errno == EPERM)
+ res = false;
supported_types[prog_type] |= res;
@@ -501,6 +508,10 @@ probe_map_type(enum bpf_map_type map_type, const char *define_prefix,
res = bpf_probe_map_type(map_type, ifindex);
+ /* Probe result depends on the success of map creation, no additional
+ * check required for unprivileged users
+ */
+
maxlen = sizeof(plain_desc) - strlen(plain_comment) - 1;
if (strlen(map_type_name[map_type]) > maxlen) {
p_info("map type name too long");
@@ -520,12 +531,17 @@ probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type,
const char *define_prefix, unsigned int id,
const char *ptype_name, __u32 ifindex)
{
- bool res;
+ bool res = false;
- if (!supported_type)
- res = false;
- else
+ if (supported_type) {
res = bpf_probe_helper(id, prog_type, ifindex);
+ /* Probe may succeed even if program load fails, for
+ * unprivileged users check that we did not fail because of
+ * insufficient permissions
+ */
+ if (run_as_unprivileged && errno == EPERM)
+ res = false;
+ }
if (json_output) {
if (res)
@@ -720,6 +736,65 @@ static void section_misc(const char *define_prefix, __u32 ifindex)
print_end_section();
}
+static int handle_perms(void)
+{
+ cap_value_t cap_list[1] = { CAP_SYS_ADMIN };
+ bool has_sys_admin_cap = false;
+ cap_flag_value_t val;
+ int res = -1;
+ cap_t caps;
+
+ caps = cap_get_proc();
+ if (!caps) {
+ p_err("failed to get capabilities for process: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ if (cap_get_flag(caps, CAP_SYS_ADMIN, CAP_EFFECTIVE, &val)) {
+ p_err("bug: failed to retrieve CAP_SYS_ADMIN status");
+ goto exit_free;
+ }
+ if (val == CAP_SET)
+ has_sys_admin_cap = true;
+
+ if (!run_as_unprivileged && !has_sys_admin_cap) {
+ p_err("full feature probing requires CAP_SYS_ADMIN, run as root or use 'unprivileged'");
+ goto exit_free;
+ }
+
+ if ((run_as_unprivileged && !has_sys_admin_cap) ||
+ (!run_as_unprivileged && has_sys_admin_cap)) {
+ /* We are all good, exit now */
+ res = 0;
+ goto exit_free;
+ }
+
+ /* if (run_as_unprivileged && has_sys_admin_cap), drop CAP_SYS_ADMIN */
+
+ if (cap_set_flag(caps, CAP_EFFECTIVE, ARRAY_SIZE(cap_list), cap_list,
+ CAP_CLEAR)) {
+ p_err("bug: failed to clear CAP_SYS_ADMIN from capabilities");
+ goto exit_free;
+ }
+
+ if (cap_set_proc(caps)) {
+ p_err("failed to drop CAP_SYS_ADMIN: %s", strerror(errno));
+ goto exit_free;
+ }
+
+ res = 0;
+
+exit_free:
+ if (cap_free(caps) && !res) {
+ p_err("failed to clear storage object for capabilities: %s",
+ strerror(errno));
+ res = -1;
+ }
+
+ return res;
+}
+
static int do_probe(int argc, char **argv)
{
enum probe_component target = COMPONENT_UNSPEC;
@@ -728,14 +803,6 @@ static int do_probe(int argc, char **argv)
__u32 ifindex = 0;
char *ifname;
- /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN).
- * Let's approximate, and restrict usage to root user only.
- */
- if (geteuid()) {
- p_err("please run this command as root user");
- return -1;
- }
-
set_max_rlimit();
while (argc) {
@@ -784,6 +851,9 @@ static int do_probe(int argc, char **argv)
if (!REQ_ARGS(1))
return -1;
define_prefix = GET_ARG();
+ } else if (is_prefix(*argv, "unprivileged")) {
+ run_as_unprivileged = true;
+ NEXT_ARG();
} else {
p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?",
*argv);
@@ -791,6 +861,12 @@ static int do_probe(int argc, char **argv)
}
}
+ /* Full feature detection requires CAP_SYS_ADMIN privilege.
+ * Let's approximate, and warn if user is not root.
+ */
+ if (handle_perms())
+ return -1;
+
if (json_output) {
define_prefix = NULL;
jsonw_start_object(json_wtr);
@@ -821,7 +897,7 @@ static int do_help(int argc, char **argv)
}
fprintf(stderr,
- "Usage: %s %s probe [COMPONENT] [full] [macros [prefix PREFIX]]\n"
+ "Usage: %s %s probe [COMPONENT] [full] [unprivileged] [macros [prefix PREFIX]]\n"
" %s %s help\n"
"\n"
" COMPONENT := { kernel | dev NAME }\n"