From 0b3b9ca3d154486baa08a41cbc62fde67ba8c6c3 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Wed, 29 Apr 2020 15:45:06 +0100 Subject: [PATCH] tools: bpftool: Make libcap dependency optional The new libcap dependency is not used for an essential feature of bpftool, and we could imagine building the tool without checks on CAP_SYS_ADMIN by disabling probing features as an unprivileged users. Make it so, in order to avoid a hard dependency on libcap, and to ease packaging/embedding of bpftool. Signed-off-by: Quentin Monnet Signed-off-by: Daniel Borkmann Acked-by: John Fastabend Link: https://lore.kernel.org/bpf/20200429144506.8999-4-quentin@isovalent.com --- .../bpf/bpftool/Documentation/bpftool-feature.rst | 4 +++- tools/bpf/bpftool/Makefile | 13 +++++++---- tools/bpf/bpftool/feature.c | 26 ++++++++++++++++++++++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/tools/bpf/bpftool/Documentation/bpftool-feature.rst b/tools/bpf/bpftool/Documentation/bpftool-feature.rst index ca08594..1fa755f 100644 --- a/tools/bpf/bpftool/Documentation/bpftool-feature.rst +++ b/tools/bpf/bpftool/Documentation/bpftool-feature.rst @@ -55,7 +55,9 @@ DESCRIPTION that case usually represent a small subset of the parameters supported by the system. Unprivileged users MUST use the **unprivileged** keyword: This is to avoid misdetection if - bpftool is inadvertently run as non-root, for example. + bpftool is inadvertently run as non-root, for example. This + keyword is unavailable if bpftool was compiled without + libcap. **bpftool feature probe dev** *NAME* [**full**] [**macros** [**prefix** *PREFIX*]] Probe network device for supported eBPF features and dump diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 89d7962..2759f9c 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -55,16 +55,15 @@ ifneq ($(EXTRA_LDFLAGS),) LDFLAGS += $(EXTRA_LDFLAGS) endif -LIBS = $(LIBBPF) -lelf -lz -lcap - INSTALL ?= install RM ?= rm -f CLANG ?= clang FEATURE_USER = .bpftool -FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib \ +FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \ + clang-bpf-global-var +FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \ clang-bpf-global-var -FEATURE_DISPLAY = libbfd disassembler-four-args zlib clang-bpf-global-var check_feat := 1 NON_CHECK_FEAT_TARGETS := clean uninstall doc doc-clean doc-install doc-uninstall @@ -90,6 +89,12 @@ ifeq ($(feature-reallocarray), 0) CFLAGS += -DCOMPAT_NEED_REALLOCARRAY endif +LIBS = $(LIBBPF) -lelf -lz +ifeq ($(feature-libcap), 1) +CFLAGS += -DUSE_LIBCAP +LIBS += -lcap +endif + include $(wildcard $(OUTPUT)*.d) all: $(OUTPUT)bpftool diff --git a/tools/bpf/bpftool/feature.c b/tools/bpf/bpftool/feature.c index 952f4b1..f54347f 100644 --- a/tools/bpf/bpftool/feature.c +++ b/tools/bpf/bpftool/feature.c @@ -6,7 +6,9 @@ #include #include #include +#ifdef USE_LIBCAP #include +#endif #include #include @@ -37,7 +39,9 @@ static const char * const helper_name[] = { #undef BPF_HELPER_MAKE_ENTRY static bool full_mode; +#ifdef USE_LIBCAP static bool run_as_unprivileged; +#endif /* Miscellaneous utility functions */ @@ -475,11 +479,13 @@ probe_prog_type(enum bpf_prog_type prog_type, bool *supported_types, } res = bpf_probe_prog_type(prog_type, ifindex); +#ifdef USE_LIBCAP /* 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; +#endif supported_types[prog_type] |= res; @@ -535,12 +541,14 @@ probe_helper_for_progtype(enum bpf_prog_type prog_type, bool supported_type, if (supported_type) { res = bpf_probe_helper(id, prog_type, ifindex); +#ifdef USE_LIBCAP /* 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; +#endif } if (json_output) { @@ -738,6 +746,7 @@ static void section_misc(const char *define_prefix, __u32 ifindex) static int handle_perms(void) { +#ifdef USE_LIBCAP cap_value_t cap_list[1] = { CAP_SYS_ADMIN }; bool has_sys_admin_cap = false; cap_flag_value_t val; @@ -793,6 +802,18 @@ exit_free: } return res; +#else + /* Detection assumes user has sufficient privileges (CAP_SYS_ADMIN). + * We do not use libpcap so let's approximate, and restrict usage to + * root user only. + */ + if (geteuid()) { + p_err("full feature probing requires root privileges"); + return -1; + } + + return 0; +#endif /* USE_LIBCAP */ } static int do_probe(int argc, char **argv) @@ -852,8 +873,13 @@ static int do_probe(int argc, char **argv) return -1; define_prefix = GET_ARG(); } else if (is_prefix(*argv, "unprivileged")) { +#ifdef USE_LIBCAP run_as_unprivileged = true; NEXT_ARG(); +#else + p_err("unprivileged run not supported, recompile bpftool with libcap"); + return -1; +#endif } else { p_err("expected no more arguments, 'kernel', 'dev', 'macros' or 'prefix', got: '%s'?", *argv); -- 2.7.4